簡體   English   中英

沒有屬性的Unity中的Setter /屬性注入

[英]Setter / property injection in Unity without attributes

我正在一個將Unity框架用作IoC容器的項目中。 我的問題涉及使用屬性或setter注入將可選依賴項(在這種情況下為記錄器)注入幾個類中。

我不想讓這些類的所有構造函數具有這些可選的依賴關系,但是我找不到在Unity中處理此問題的好方法。 根據MSDN文檔 ,您可以通過在屬性中添加一個屬性來做到這一點:

private ILogger logger; 

[Dependency]
public ILogger Logger
{
get { return logger; }
  set { logger = value; }
}

我覺得這很丑。 StructureMap中,可以執行以下操作來設置給定類型的所有屬性:

SetAllProperties(policy => policy.OfType<ILog>());

有誰知道在Unity中是否可以做類似的事情?

編輯:

Kim Major建議使用這種方法 ,也可以通過代碼來實現。

我對如何針對所有匹配屬性自動執行此操作的示例感興趣。

我也不喜歡那些屬性

您可以使用unity容器的Configure方法完成所有操作:

首先注冊類型

unityContainer.RegisterType<MyInterface,MyImpl>(
                     new ContainerControlledLifetimeManager());

如果您有多個構造函數,則必須執行此操作,以便Unity調用無參數構造函數(如果沒有設置,則Unity將成為最胖的構造函數)

unityContainer.Configure<InjectedMembers>()
                            .ConfigureInjectionFor<MyImpl>(
                                new InjectionConstructor()); 

設置屬性依賴

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                         new InjectionProperty(
                             "SomePropertyName",
                                new ResolvedParameter<MyOtherInterface>()));

配置方法依賴

unityContainer.Configure<InjectedMembers>()
                    .ConfigureInjectionFor<MyImpl>(
                        new InjectionMethod(
                            "SomeMethodName",
                            new ResolvedParameter<YetAnotherInterface>()));

我也不是使用屬性的忠實擁護者,但我也不喜歡.Configure<InjectedMembers>()方法,因為您必須綁定到特定的屬性名稱和特定的值。 我發現給您最大靈活性的方法是創建自己的構建器策略。

我創建了這個簡單的類,該類對正在構建的對象的屬性進行迭代,如果該屬性的類型已在unity容器中注冊,則設置其屬性值。

public class PropertyInjectionBuilderStrategy:BuilderStrategy
{
    private readonly IUnityContainer _unityContainer;

    public PropertyInjectionBuilderStrategy(IUnityContainer unityContainer)
    {
        _unityContainer = unityContainer;
    }

    public override void PreBuildUp(IBuilderContext context)
    {
        if(!context.BuildKey.Type.FullName.StartsWith("Microsoft.Practices"))
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(context.BuildKey.Type);

            foreach (PropertyDescriptor property in properties)
            {
                if(_unityContainer.IsRegistered(property.PropertyType)
                   && property.GetValue(context.Existing) == null)
                {
                    property.SetValue(context.Existing,_unityContainer.Resolve(property.PropertyType));
                }
            }
        }
    }
}

您可以通過創建BuilderStrategy來注冊UnityContainerExtension 這是一個例子:

public class TestAppUnityContainerExtension:UnityContainerExtension
{
    protected override void Initialize()
    {
        Context.Strategies.Add(new PropertyInjectionBuilderStrategy(Container), UnityBuildStage.Initialization);
    }
}

這樣會在Unity容器中注冊:

IUnityContainer container = new UnityContainer();
container.AddNewExtension<TestAppUnityContainerExtension>();

希望這可以幫助,
馬修

您發布的原始示例確實很繁瑣,但是您可以使用如下所示的自動實現的屬性來幫助清理該代碼:

[Dependency]
public ILogger Logger { get; set; }

使用Unity 2.1,這也可以正常工作:

var container = new UnityContainer()
            .RegisterType<ILogger, Logger>()
            .RegisterType<ISomeInterface, SomeImplementaion>(
                                new InjectionProperty("Logger", new ResolvedParameter<ILogger>()));

SomeImplementaion類的注入屬性只是

public ILogger Logger { get; set; }

您可以嘗試以下方法:

MyClass中的這段代碼

[InjectionMethod]
public void Initialize(
                 [Dependency] ILogger logger

然后通過以下方式調用它:

unitycontainer.BuildUp<MyClass>(new MyClass());

然后unity將使用容器中的依賴項調用Initialize方法,然后可以將其保存在MyClass或其他類的私有變量中。

以下演練顯示了通過配置完成此操作的一種方法。 您當然也可以通過代碼進行連接。 http://aardvarkblogs.wordpress.com/unity-container-tutorials/10-setter-injection/

看一下用於基於約定的配置的UnityConfiguration項目。 它工作得很好,盡管在使用ResolveAll<IType>()查找多個實現時遇到問題。 看到這個問題

container.RegisterInstance(typeof (ILogger), LoggerService.GetLogger());
container.Configure(c => c.Scan(scan =>
                    {
                        scan.AssembliesInBaseDirectory(a => a.FullName.StartsWith("My.Company")); // Filter out everthing that are not from my assemblies
                        scan.InternalTypes();
                        scan.With<SetAllPropertiesConvention>().OfType<ILogger>();
                    }));

您可以將類容器注入統一容器。

例如,如果您有一個類“ MyClass”,並且對兩個接口“ IExample1”和“ IExample2”具有依賴關系,並且不想在構造函數中為其定義參數,則請按照以下步驟操作

步驟1.在統一容器中注冊兩個接口

IUnityContainer container = new UnityContainer();
container.RegisterType<IExample1,Impl1>();
container.RegisterType<IExample2,Impl2>();
//resolve class MyClass
var myClass = container.Resolve<MyClass>();


步驟2。您的班級應如下所示

public class MyClass
{
     IExample1 ex1;
     IExample2 ex2
     public MyClass(IUnityContainer container)
     {
        /* This unity container is same unity container that we used in step 
           1 to register and resolve classes. So you can use this container to resolve
           all the dependencies. */
       ex1= container.Resolve<IExample1>(); // will give you object of Impl1
       ex2= container.Resolve<IExample2>(); // will give you object of Impl2
     }
}

第三步 這樣,您可以解析任何數量的依賴項,而無需在構造函數中定義它們。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM