示例:
IApple
和实施Apple
。 Apple
的构造函数:
public Apple(IVitamin vitamin, int size)
我可以注册所有DI和IApple:
container.RegisterType<IApple,Apple>();
container.RegisterInstance<IVitamin>(vitamin);
我现在可以在创建apple实例时覆盖参数以插入int size参数:
var apple = container.Resolve<IApple>(new ParameterOverrides<Apple> {{"size", 9001}}
你必须在那里写参数的字符串(&#34; size&#34;)似乎很麻烦。当涉及其他参数时,这是否是首选DI?或者我是否必须创建一个处理该工作的AppleFactory(或者通常是工厂)? (对于每个具有非DI属性以及DI属性的类,必须编写工厂似乎有点过分。
或者你不应该手动覆盖和设置属性吗?
var apple = container.Resolve<IApple>();
apple.Size = 9001;
这样代码逻辑就会从构造函数转移到属性的setter。
答案 0 :(得分:3)
你必须在那里写参数的字符串似乎很麻烦(&#34; size&#34;)
是的,它很难看,但是没有办法绕过它,至少不是Unity。
为每个具有非DI属性以及DI属性的类编写工厂似乎有点过分
是的,但它可能是你应该做的。您的大多数代码不应直接依赖于容器。
如果你是一个工厂,参数覆盖并不是那么难看,因为你可以使用nameof
而不是字符串:
class AppleFactory : IAppleFactory
{
...
public IApple CreateApple(int size)
{
return _container.Resolve<IApple>(new ParameterOverrides<Apple> {{nameof(size), size}};
}
}
另一种方法是使用我的Unity.Extras.AutoFactory扩展程序,但请记住它处于alpha状态...
答案 1 :(得分:1)
我建议你想为什么要以这种方式向课堂注入integer
。如果使用unity实例化的每个Apple
都注入了相同的值,那么该值是否为常数?如果是的话,你真的不需要注射它。它可以只是Apple
的一部分。但是在您的示例中,如果Apple
表示实体或具有状态且可以具有不同大小的对象,Factory
肯定似乎是更好的选择。 Factory
将在初始化期间设置属性值。如果您正在测试代码,那么您将自己帮忙将这些决策转移到Factory
并保持IoC容器配置专注于构建依赖树而不是处理初始状态对象的值。
答案 2 :(得分:1)
我认为你的例子太简单了。如果您要创建不同大小的苹果,您可能不会从容器中解析它们(通过容器创建苹果的方式有点奇怪,它看起来更适合{{ 1}}然后factory
)。
不要忘记容器的主要目的是连接复杂的对象组合/依赖项,这些组件/依赖项应该能够从容器的当前状态创建。当你发现自己为Resolve方法提供参数时,我认为你应该停下来并试图避免它,可能是一些重新设计,重构是正确的方向。
旁注:
在大多数情况下,当我需要注入原语时,我会使用像这样的结构/类
container
现在我可以在public struct AppleSize {
public int Value { get; }
.....
}
中注册AppleSize
的实例
Apple构造函数将使用container
而不是AppleSize
。避免注册原语。更好地使用更具描述性的结构/类定义。
如果场景更强复杂(要注入的原语可能依赖于太多的参数,需要计算/操作)那么我会创建int
到封装任何与创建对象相关的操作,这与我认为的场景更接近。