温莎城堡:强制解析器使用指定的构造函数
示例如下:
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<IComponentA>()
.ImplementedBy<ComponentA>())
.Register(Component
.For<IComponentB>()
.ImplementedBy<ComponentB>())
.Register(Component
.For<IComponentC>()
.UsingFactoryMethod(() => new ComponentC(
container.Resolve<IComponentB>())));
它有效,但温莎城堡可能提供了一些更好的方法来做到这一点?
非常感谢任何帮助。
谢谢。
Here is the example:
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");
}
};
All these components are registered in Castle Windsor container.
But class ComponentC
has 2 overloaded constructors. Any of them can be used when ComponentC
is being activated.
I need ComponentC(IComponentB b)
constructor to be used.
For a moment I'm using UsingFactoryMethod() method to resolve that:
container
.Register(Component
.For<IComponentA>()
.ImplementedBy<ComponentA>())
.Register(Component
.For<IComponentB>()
.ImplementedBy<ComponentB>())
.Register(Component
.For<IComponentC>()
.UsingFactoryMethod(() => new ComponentC(
container.Resolve<IComponentB>())));
It works, but probably Castle Windsor provides some better way to do that?
Any help is really appreciated.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Windsor 不提供对这种情况的支持,因为它打破了它(以及大多数容器)运行所基于的不成文假设之一:“所有构造函数都是平等创建的”。
这意味着,无论选择哪个构造函数,组件的行为都不应该有功能差异。在所有条件相同的情况下,组件的依赖项越多,它拥有的功能就越多,这就是为什么 Windsor 会倾向于首先选择更贪婪的构造函数,但如果像你这样,我会说发生了两种情况之一:
我见过的另一种情况是这样的:
虽然这乍一看似乎是一个聪明的主意,但充其量它是多余的、令人困惑的和不必要的。如果您的情况类似于此,我只需删除第二个构造函数。
Windsor doesn't provide support for this scenario, because it breaks one of the unwritten assumptions it (and most containers) operates based on: "all constructors are created equal".
What that means, is that regardless of which constructor it choses there should be no functional differences in the behaviour of the component. All things being equal the more dependencies a component has the more capabilities it has, that's why Windsor will tend to pick greedier constructors first, but in case like yours I'd say either of two things are happening:
Another scenario I've seen is something like that:
While this might seem like a clever idea at first, at best it's superfluous, confusing and unnecessary. If your case looks like this one, I'd just remove the second constructor.
嗯,这很糟糕,但有一种方法(过去我不得不使用 Linq2Sql DataContext 对象来做到这一点)。您创建一个装饰器类并注册它。
假设你有这个接口:
并且你有一个如下的实现:
但正如示例所示,由于某种原因,Windsor 调用了错误的 ctor,否则你无法说服它(正如 Krzysztof 正确指出的那样)。然后,您可以按如下方式创建装饰器类,该类只有一个构造函数,从而消除了歧义:
然后您可以注册该类:
当然,最好不要使用这种奇怪的默认值-在其他构造函数中发生的事情(搜索对于“穷人的依赖注入”),但在您无法控制您真正想要的类的情况下(就像我在 Linq2Sql 中一样,或者如果它这将是对 API 的重大更改),那么这可能会让您摆脱麻烦。
Umm, it's awful but there is one way (I've had to do this with Linq2Sql DataContext objects in the past). You create a decorator class and register that instead.
Let's say you have this interface:
And you have an implementation as follows:
But as the example suggests, for some reason Windsor is calling the wrong ctor and you can't convince it otherwise (as Krzysztof correctly points out). Then you could create the decorator class as follows, which only has one constructor and thus removes the ambiguity:
You'd then register that class instead:
Of course better would be to not have this weird default-values-in-other-constructors thing going on (search for "Poor-man's Dependency Injection"), but in the case where you're not in control of the class you actually want (like I was in Linq2Sql, or if it would be a breaking change to an API) then this might get you out of trouble.