Автоматический вводят свойство для типов регистра без DependencyAttribute

Register<IA, A>();

class B { public IA A {get;set;}} 

//container inject this property because IA was registered

В autofac можно сделать

builder.RegisterType<A>().InjectProperties();

для этого.

Действительно ли там кто-либо - расширение для единицы, чтобы сделать это? Или может быть расширение, которое я могу использовать, поскольку образец для реализует эту опцию один?

1
задан dotneter 9 May 2010 в 08:47
поделиться

1 ответ

Это не простая задача. Для ее решения необходимо изменить поведение 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

2
ответ дан 3 September 2019 в 00:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: