使用 Unity 容器进行 DI - 使用其他参数解析的最佳实践?



示例:

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}}

您必须在其中编写参数的字符串("size")似乎很麻烦。当涉及其他参数时,这是执行 DI 的首选方法吗?还是我必须创建一个AppleFactory(或一般的工厂)来处理这个问题?(必须为每个具有非 DI 属性和 DI 属性的类编写一个工厂似乎有点过分了。

还是不应该手动覆盖和设置属性?

var apple = container.Resolve<IApple>();
apple.Size = 9001;

这样,代码逻辑将从属性的构造函数转移到 setter。

您必须在其中写入参数的字符串("size")似乎很麻烦

是的,它很丑陋,但没有办法绕过它,至少在 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 状态......

我建议想想你为什么要以这种方式在类中注入integer。如果使用 unity 实例化的每个Apple都被注入相同的值,则该值是常量吗?如果是,您实际上不需要注入它。它可以只是Apple的一部分。但是在您的示例中,如果Apple表示具有状态的实体或对象并且可以具有不同的大小,则Factory绝对是更好的选择。Factory最终将在初始化期间设置属性的值。如果您正在测试代码,您将帮助自己将这些类型的决策移动到Factory中,并使 IoC 容器配置专注于构建依赖树,而不是处理对象初始状态的值。

我认为你的例子太简单了。如果您要创建不同大小的苹果,则可能不会从容器中解析它们(通过容器创建苹果的方式有点奇怪,它看起来更适合factory然后container)。

不要忘记,容器的主要目的是连接复杂的对象组合/依赖项,这些组合/依赖项应该能够从容器的当前状态创建。当你发现自己为 Resolve 方法提供参数时,我认为你应该停下来并尝试避免它,可能是一些重新设计,重构是正确的方向。

旁注

在大多数情况下,当我需要注入原语时,我会使用这样的结构/类

public struct AppleSize {
public int Value { get; }
.....
}

现在我可以在container中注册AppleSize实例 苹果构造函数将使用AppleSize而不是int。避免注册基元。最好使用更具描述性的结构/类定义。

如果场景更复杂(要注入的原语可能取决于太多参数并且需要计算/操作),那么我会创建factory封装与对象创建相关的任何操作,我认为这更接近您的场景。

最新更新