[英]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.