2010-05-09 32 views
1
Register<IA, A>(); 

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

//container inject this property because IA was registered 

在autofac你可以做自動注入的寄存器類型屬性,而不DependencyAttribute

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

這一點。

是否有任何擴展爲統一做到這一點?或者可以作爲我自己實現該功能的示例使用的擴展名?

回答

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,你可以在源代碼中找到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()); 
     } 
    } 

您可以下載源文件e從這裏開始http://92.248.232.12/UnitTest1.zip