温莎城堡:强制解析器使用指定的构造函数
本文关键字:构造函数 城堡 | 更新日期: 2023-09-27 18:12:33
示例如下:
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
有两个重载的构造函数。当ComponentC
被激活时,它们中的任何一个都可以使用。
我需要使用ComponentC(IComponentB b)
构造器
暂时我使用UsingFactoryMethod()方法来解决:
container
.Register(Component
.For<IComponentA>()
.ImplementedBy<ComponentA>())
.Register(Component
.For<IComponentB>()
.ImplementedBy<ComponentB>())
.Register(Component
.For<IComponentC>()
.UsingFactoryMethod(() => new ComponentC(
container.Resolve<IComponentB>())));
它是有效的,但也许温莎城堡提供了更好的方法?
任何帮助都非常感谢。
谢谢。
Windsor不支持这种场景,因为它打破了它(和大多数容器)基于的一个不成文的假设:"所有构造函数都是平等的"。
这意味着,无论它选择哪个构造函数,组件的行为都不应该有功能上的差异。在所有条件相同的情况下,组件拥有的依赖越多,它拥有的功能就越多,这就是为什么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<object> emptyArrayFromWindsor)
{
_logger = logger;
PutTheItemsSomewhere(emptyArrayFromWindsor);
}
public void DoSomething()
{
// Something that relies on the list of items...
}
}
但正如这个例子所表明的那样,由于某种原因,温莎打错了医生,你无法说服它(正如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<IService>()
.ImplementedBy<SpecificCtorServiceDecorator>());
当然最好不要有这种奇怪的默认值在其他构造函数的事情(搜索"穷人的依赖注入"),但在你不控制你真正想要的类的情况下(像我在Linq2Sql,或者如果它将是一个突破性的改变一个API),那么这可能会让你摆脱麻烦。