没有DependencyAttribute的寄存器类型的自动注入属性

时间:2010-05-09 06:53:43

标签: .net unity-container autofac

Register<IA, A>();

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

//container inject this property because IA was registered

在autofac中你可以做到

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

为此。

有没有任何扩展团结来做到这一点?或者可以作为我自己实施此功能的样本的扩展名吗?

1 个答案:

答案 0 :(得分:2)

这不是一项简单的任务。要解决它,您应该更改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,你可以在团结的源代码中找到它。

之后,您需要使用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

下载源文件