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

问题描述 投票:3回答:3

例:

IApple和实施AppleApple的构造函数:

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

你必须在那里写入参数的字符串(“大小”)似乎很麻烦。当涉及其他参数时,这是否是首选DI?或者我是否必须创建一个处理该工作的AppleFactory(或者通常是工厂)? (对于具有非DI属性以及DI属性的每个类,必须编写工厂似乎有点过头了。

或者你不应该手动覆盖和设置属性?

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

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

c# .net unity-container
3个回答
3
投票

你必须在那里写参数的字符串(“大小”)似乎很麻烦

是的,这很难看,但是没有办法绕过它,至少不是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
投票

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


1
投票

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

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

边注:

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

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

现在我可以在AppleSize中注册container的实例,Apple构造函数将使用AppleSize而不是int。避免注册原语。更好地使用更具描述性的结构/类定义。

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

© www.soinside.com 2019 - 2024. All rights reserved.