C# Castle Windsor:强制解析程序使用指定的构造函数

C# Castle Windsor:强制解析程序使用指定的构造函数,c#,.net,dependency-injection,castle-windsor,ioc-container,C#,.net,Dependency Injection,Castle Windsor,Ioc Container,以下是一个例子: interface IComponentA {}; class ComponentA : IComponentA { }; interface IComponentB { }; class ComponentB : IComponentB { }; interface IComponentC { }; class ComponentC : IComponentC { public ComponentC(IComponentA a) {

以下是一个例子:

interface IComponentA {};

class ComponentA : IComponentA { };

interface IComponentB { };

class ComponentB : IComponentB { };

interface IComponentC { };

class ComponentC : IComponentC
{
    public ComponentC(IComponentA a)
    {
        Console.WriteLine("Constructor A"); 
    }

    public ComponentC(IComponentB b) 
    {
        Console.WriteLine("Constructor B");
    }
};
所有这些组件均在Castle Windsor容器中注册

但是类
ComponentC
有2个重载构造函数。当激活
组件C
时,可以使用其中任何一个

我需要使用
ComponentC(IComponentB)
构造函数

目前,我正在使用FactoryMethod()方法来解决这个问题:

container
    .Register(Component
        .For<IComponentA>()
        .ImplementedBy<ComponentA>())
    .Register(Component
        .For<IComponentB>()
        .ImplementedBy<ComponentB>())
    .Register(Component
        .For<IComponentC>()
        .UsingFactoryMethod(() => new ComponentC(
            container.Resolve<IComponentB>())));
容器
.寄存器(组件)
.对于()
.ImplementedBy())
.寄存器(组件)
.对于()
.ImplementedBy())
.寄存器(组件)
.对于()
.使用FactoryMethod(()=>新组件C(
container.Resolve());
这是可行的,但温莎城堡可能提供了更好的方法

非常感谢您的帮助


谢谢。

温莎不支持这种情况,因为它打破了它(和大多数容器)运行时基于的一个不成文假设:“所有构造函数都是平等的”

这意味着,无论选择哪个构造函数,组件的行为都不应该有功能上的差异。在所有条件相同的情况下,一个组件的依赖性越强,它的功能就越多,这就是为什么Windsor倾向于首先选择更贪婪的构造函数,但如果像您这样的情况,我想说的是,两种情况中的一种正在发生:

  • 您的组件实际上可能是伪装成一个组件的两个组件。在这种情况下,您可能会想要拆分它
  • 您的组件实际上使用它所拥有的两个依赖项进行操作,因此它应该有一个构造函数来接受这两个依赖项
我看到的另一个场景是这样的:

public class Foo
{
   public Foo(ISession session){/*code*/}
   public Foo(ISessionFactory factory):this(factory.OpenSession()){}
}

虽然一开始这似乎是一个聪明的想法,但充其量它是多余的、令人困惑的和不必要的。如果您的案例与此类似,我将删除第二个构造函数

嗯,这很糟糕,但有一种方法(我过去不得不使用Linq2Sql DataContext对象来实现这一点)。您创建了一个decorator类并注册它

假设您有这个接口:

public interface IService 
{
    void DoSomething();
}
您的实现如下所示:

public class Service : IService
{
    private readonly ILogger _logger;

    public Service(ILogger logger)
        : this(logger, SomeDefaultListOfThings())
    {
    }

    // Let's say Windsor is calling this ctor for some reason (ArrayResolver?)
    public Service(ILogger logger, IEnumerable<object> emptyArrayFromWindsor)
    {
        _logger = logger;
        PutTheItemsSomewhere(emptyArrayFromWindsor);
    }

    public void DoSomething()
    {
        // Something that relies on the list of items...
    }
}
然后您将注册该类:

container.Register(
    Component.For<IService>()
             .ImplementedBy<SpecificCtorServiceDecorator>());
container.Register(
用于()的组件
.ImplementedBy());

当然,最好不要在其他构造函数中使用这种奇怪的默认值(),但是如果您不能控制实际需要的类(比如我在Linq2Sql中,或者如果它是对API的一个突破性更改),那么这可能会帮您摆脱麻烦。

如果它适合您的模型,您可以尝试使用类型化工厂设施。我相信它会自动选择与传递给工厂方法的参数相匹配的构造函数。这意味着您必须有一个工厂和该类型的实例才能传入,tho。如果您最终保留了现有代码,并且如果在同一安装程序中注册这两个代码,并且如果<代码>组件B 不存在依赖关系,请考虑跳过“代码> > ICOMPONTUNTB< <代码> />代码> ICOMPONTRON/<代码>的注册。一些注释(例如,
isubdependencysolver
)也可能有用。为什么使用哪个.ctor会有关系?@Krzysztof Koźmic例如构造函数
ComponentC(IComponentA)
自行创建
IComponentB
,而不使用容器中的
IComponentB
<代码>组件C(IComponentB)自行创建
IComponentA
,不使用容器中的
IComponentA
。因此,
ComponentC
在这些情况下的行为是不同的。我想说,你可能在你的班上有两个职责,也许你应该把它们分开?很好的解释。我同意这一点。谢谢。你的第一个要点把我带到了固体范式的单一责任原则。真是令人印象深刻的回答!你的回答让我大开眼界,解决了我队友观察到的一个神秘的温莎城堡行为。我们正在进行一个ASP.net MVC项目,该项目中的控制器具有重载构造函数,我很困惑,为什么DI容器总是使用最多的参数调用构造函数。
container.Register(
    Component.For<IService>()
             .ImplementedBy<SpecificCtorServiceDecorator>());