Register<IA, A>();
class B { public IA A {get;set;}}
//container inject this property because IA was registered
В autofac можно сделать
builder.RegisterType<A>().InjectProperties();
для этого.
Действительно ли там кто-либо - расширение для единицы, чтобы сделать это? Или может быть расширение, которое я могу использовать, поскольку образец для реализует эту опцию один?
Это не простая задача. Для ее решения необходимо изменить поведение Unity по умолчанию политики селектора свойств. Вы можете изменить его. Вот что я могу предложить
namespace Microsoft.Practices.Unity.ObjectBuilder
{
public class ResolveBecouseWeCanPropertySelectorPolicy : PropertySelectorBase<DependencyResolutionAttribute>
{
private readonly IUnityContainer container;
public ResolveBecouseWeCanPropertySelectorPolicy(IUnityContainer container) {
this.container = container;
}
public override IEnumerable<SelectedProperty> SelectProperties(IBuilderContext context, IPolicyList resolverPolicyDestination) {
Type t = context.BuildKey.Type;
foreach (
PropertyInfo prop in
t.GetProperties(BindingFlags.Public | BindingFlags.SetProperty | BindingFlags.Instance)) {
if (prop.GetIndexParameters().Length == 0 &&
prop.CanWrite
&& prop.IsDefined(typeof (DependencyResolutionAttribute), false)
) //Default behaviour
{
yield return CreateSelectedProperty(context, resolverPolicyDestination, prop);
}
//Alternate behaviour
else if (prop.GetIndexParameters().Length == 0 &&
prop.CanWrite &&
container.IsRegistered(prop.PropertyType)//don't mind about Dependency attribute if we can resolve it - we would
) {
{
yield return CreateSelectedPropertyForResolveBecouseWeCan(context, resolverPolicyDestination, prop);
}
}
}
}
private SelectedProperty CreateSelectedProperty(IBuilderContext context, IPolicyList resolverPolicyDestination, PropertyInfo property) {
return DoCreateSelectedProperty(property, resolverPolicyDestination, CreateResolver(property), context);
}
private static SelectedProperty CreateSelectedPropertyForResolveBecouseWeCan(IBuilderContext context, IPolicyList resolverPolicyDestination, PropertyInfo property) {
IDependencyResolverPolicy dependencyResolverPolicy = new DependencyAttribute().CreateResolver(property.PropertyType);
return DoCreateSelectedProperty(property, resolverPolicyDestination, dependencyResolverPolicy, context);
}
private static SelectedProperty DoCreateSelectedProperty(PropertyInfo property, IPolicyList resolverPolicyDestination, IDependencyResolverPolicy dependencyResolverPolicy, IBuilderContext context) {
string key = Guid.NewGuid().ToString();
var result = new SelectedProperty(property, key);
resolverPolicyDestination.Set( dependencyResolverPolicy, key);
DependencyResolverTrackerPolicy.TrackKey(context.PersistentPolicies,
context.BuildKey,
key);
return result;
}
protected override IDependencyResolverPolicy CreateResolver(PropertyInfo property)
{
var attributes =
property.GetCustomAttributes(typeof (DependencyResolutionAttribute), false)
.OfType<DependencyResolutionAttribute>()
.ToList();
Debug.Assert(attributes.Count == 1);
return attributes[0].CreateResolver(property.PropertyType);
}
}
}
Это измененная DefaultUnityPropertySelectorPolicy, которую вы можете найти в исходном коде unity.
После этого вам нужно переопределить поведение по умолчанию, используя механизм UnityContainerExtension
.
public class ResolveBecouseWeCanUnityContainerExtension : UnityContainerExtension {
protected override void Initialize() {
Context.Policies.SetDefault<IPropertySelectorPolicy>(
new ResolveBecouseWeCanPropertySelectorPolicy(Container));
}
}
Теперь представим, что у вас есть следующие классы
public interface IConcreteService {
int Val { get; set; }
}
public class ConcreteService : IConcreteService {
public int Val { get; set; }
public ConcreteService() {
}
}
public class B {
//no attribute
public IConcreteService ConcreteService { get; set; }
public int SomeVal { get; set; }
}
Теперь этот тест должен пройти
[TestMethod]
public void TestMethod1() {
var container = new UnityContainer();
container.AddExtension(new ResolveBecouseWeCanUnityContainerExtension());
container.RegisterType<IConcreteService, ConcreteService>();
var b = new B();
container.BuildUp(b);
Assert.IsNotNull(b.ConcreteService);
}
Но вы должны понимать, что этот тест не пройдет
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
var container = new UnityContainer();
container.RegisterType<IConcreteService, ConcreteService>();
var b0 = new B();
container.BuildUp(b0);
Assert.IsNull(b0.ConcreteService);
container.AddExtension(new ResolveBecouseWeCanUnityContainerExtension());
var b = new B();
container.BuildUp(b);
Assert.IsNotNull(b.ConcreteService); //dies becouse plan cashed
}
}
Обновление
Я поиграл еще немного и выяснил, как заставить этот тест работать
[TestClass]
public class UnitTest1 {
[TestMethod]
public void TestMethod1() {
var container = new UnityContainer();
container.RegisterType<IConcreteService, ConcreteService>();
var b0 = new B();
container.BuildUp(b0);
Assert.IsNull(b0.ConcreteService);
var b = new B();
container.BuildUpAndResolveAllWeCan(b);
Assert.IsNotNull(b.ConcreteService);
//check if we have no broken something and that it will work second time
var b1 = new B();
container.BuildUp(b1);
Assert.IsNull(b1.ConcreteService);
var b2 = new B();
container.BuildUpAndResolveAllWeCan(b2);
Assert.IsNotNull(b2.ConcreteService);
}
}
Это можно сделать следующим образом
public static class UnityExtensions {
public static T BuildUpAndResolveAllWeCan<T>(this IUnityContainer container, T existing) {
return BuildUpAndResolveAllWeCan(container, existing, null) ;
}
public static T BuildUpAndResolveAllWeCan<T>(this IUnityContainer container, T existing, string name) {
container.AddExtension(new ResolveBecouseWeCanUnityContainerExtension());
//we are adding __BuildUpResolveAllWeCan__ to create new IBuildPlanPolicy for type T
//and IPropertySelectorPolicy is ResolveBecouseWeCanPropertySelectorPolicy
//this will be cached so it will not hurt the performance
var buildedUp = container.BuildUp(existing, (name ?? string.Empty) + "__BuildUpResolveAllWeCan__");
container.AddExtension(new CleanUnityContainerExtension());
return buildedUp;
}
}
и добавить очищающее расширение
public class CleanUnityContainerExtension : UnityContainerExtension {
protected override void Initialize() {
Context.Policies.SetDefault<IPropertySelectorPolicy>(
new DefaultUnityPropertySelectorPolicy());
}
}
Вы можете скачать исходный файл отсюда http://92.248.232.12/UnitTest1.zip