Castle Windsor:强制解析器使用指定的构造函数

这是一个例子:

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个重载的构造函数。 当激活ComponentC时,可以使用它们中的任何一个。

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

我暂时使用UsingFactoryMethod()方法来解决这个问题:

 container .Register(Component .For() .ImplementedBy()) .Register(Component .For() .ImplementedBy()) .Register(Component .For() .UsingFactoryMethod(() => new ComponentC( container.Resolve()))); 

它有效,但可能Castle Windsor提供了一些更好的方法吗?

任何帮助都非常感谢。

谢谢。

Windsor不支持这种情况,因为它打破了(和大多数容器)基于以下操作的一个不成文的假设:“所有构造函数都是相同的”。

这意味着,无论它选择哪种构造函数,组件的行为都不应存在function差异。 在所有条件相同的情况下,组件具有的依赖性越多,它就具有越多的function,这就是为什么Windsor会首先选择贪婪的构造函数,但是如果像你的那样,我会说两件事情中的任何一件都发生了:

  • 你的组件实际上可能是伪装成一个组件的两个组件。 在这种情况下,您可能希望将其拆分。
  • 你的组件实际上确实与它具有的两个依赖项一起运行,因此它应该有一个构造函数来接受它们。

我见过的另一个场景是这样的:

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

虽然这看起来似乎是一个聪明的想法,但充其量是多余的,令人困惑和不必要的。 如果你的情况看起来像这个,我只是删除第二个构造函数。

嗯,这很糟糕,但有一种方法(过去我必须使用Linq2Sql DataContext对象)。 您创建一个装饰器类并注册它。

假设你有这个界面:

 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 emptyArrayFromWindsor) { _logger = logger; PutTheItemsSomewhere(emptyArrayFromWindsor); } public void DoSomething() { // Something that relies on the list of items... } } 

但正如这个例子所暗示的那样,由于某些原因,温莎打电话给错误的ctor而你却无法说服它(正如Krzysztof正确指出的那样)。 然后你可以创建如下的装饰器类,它只有一个构造函数 ,从而消除了歧义:

 public class SpecificCtorServiceDecorator : IService { private readonly IService _decorated; public SpecificCtorServiceDecorator(ILogger logger) { _decorated = new Service(logger); } public void DoSomething() { _decorated.DoSomething(); } } 

然后,您将注册该类:

 container.Register( Component.For() .ImplementedBy()); 

当然更好的是不要让这个奇怪的默认值在其他构造函数中继续( 搜索“穷人的dependency injection” ),但是在你无法控制类的情况下你实际上想要(就像我在Linq2Sql中,或者如果它是对API的重大改变)那么这可能会让你摆脱困境。