Unity.Resolve如何知道使用哪个构造函数?

36

给定一个具有多个构造函数的类 - 如何告诉 Resolve 使用哪个构造函数?

考虑以下示例类:

public class Foo
{
    public Foo() { }
    public Foo(IBar bar)
    {
        Bar = bar;
    }
    public Foo(string name, IBar bar)
    {
        Bar = bar;
        Name = name;
    }
    public IBar Bar { get; set; }        
    public string Name { get; set; }
}
如果我想使用 Resolve 创建类型为 Foo 的对象,那么 Resolve 将如何知道要使用哪个构造函数?我该如何告诉它使用正确的构造函数?假设我有一个已注册了 IBar 的容器-它会理解应该优先选择接受 IBar 参数的构造函数吗?如果我还指定了一个字符串-它会使用 (string, IBar) 构造函数吗?
Foo foo = unityContainer.Resolve<Foo>(); 

请忽略这个事实:如果该类只有一个构造函数,那么可能会更容易...

2个回答

63
当目标类包含多个构造函数时,Unity将使用已应用InjectionConstructor属性的构造函数。如果有多个构造函数,而没有一个带有InjectionConstructor属性,则Unity将使用具有最多参数的构造函数。如果存在多个这样的构造函数(具有相同数量参数的“最长”构造函数),则Unity将引发异常。
取自链接文本

1
正是我想要的!我只需使用[InjectionConstructor]修饰我想要使用的构造函数。 - Varga Tamas
3
那是可以节省周末的答案。定义明确。 - Teoman shipahi
我遇到了这样一种情况,Unity没有选择带有最多参数的构造函数。有两个构造函数,一个带有一个参数,另一个带有4个参数。它选择了带有一个参数的构造函数,为什么会这样呢?你有什么想法或建议,或者应该在哪里进行检查? - Don Box

35

在注册类型时,您可以像这样指定要使用的构造函数:

container.RegisterType<Foo>(
    new InjectionConstructor(
        new ResolvedParameter<IBar>()));

以上代码是根据记忆写的,但这是一般原则。在这个例子中,我选择了带有类型为IBar的单参数的构造函数。

请忽略如果该类只有一个构造函数将会更容易的事实...

我不能忽略这一点。当涉及到构造函数注入时,不确定性是设计上的问题。你基本上在说:我不确定是否关心这个依赖项。

当然,Unity可能会为您解决它,但那样您将依赖于特定容器的行为而不是正确设计API。其他容器可能有不同的行为,因此,如果您从Unity迁移到更好的容器,可能会出现微妙的错误。

可以进行DI但与容器无关的方式编写代码会更安全。


谢谢!但是我真的需要在容器中注册类型吗?我将使用容器来解析Foo的实例,但我不需要Foo在容器中。但我仍然应该使用RegisterType吗?还是只是因为我有这个特定的需求告诉它要使用哪个构造函数? - stiank81
是的,也不是。正如ozczecho所引用的那样,Unity在面对歧义时使用一种启发式方法来选择构造函数(它选择具有最多参数的构造函数)。如果您需要它偏离此算法,您必须明确告诉它。一种方法是应用InjectionConstructor属性,另一种方法是在容器中注册它。我个人更喜欢在容器中注册类型,因为这让我保持代码与容器无关。它还允许不同的容器配置(如果适用)。 - Mark Seemann
就Unity的能力而言,即使未在容器中注册,它也能解析具体类型,这是它特有的功能。某些容器支持该功能,而另一些则不支持。 - Mark Seemann
+1 你说得对,指出模糊性是一种设计问题让我意识到我应该使用参数注入而不是构造函数注入。我之所以尝试使用两个构造函数的唯一原因是为了可测试性。 - CRice

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接