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