【问题标题】:Castle Windsor multiple implementations of interfaceCastle Windsor 多种接口实现
【发布时间】:2015-09-08 11:50:15
【问题描述】:

我有以下安装程序,但由于某些奇怪的原因,它无法正确解析。我有一个接口,其中有 2 个实现,但想基于 naming conventions 注入正确的实例。

我期望在这种情况下,ICommand 的正确实例将根据它们的命名方式被注入。但是,由于某些奇怪的原因,两个控制器都选择了第一个实例,即FooCommand,因为它是在安装程序中首先定义的。

不确定我做错了什么?也许,有没有其他方法可以做到这一点?

public interface ICommand { }

public class FooCommand : ICommand { }

public class BarCommand : ICommand { }

public class SomeController : ApiController
{
    public SomeController(ICommand fooCommand) { }
}

public class HelloController : ApiController
{
    public HelloController(ICommand barCommand) { }
}

container.Register(
    Component.For<ICommand>()
        .Named("fooCommand")
        .ImplementedBy<FooCommand>()
        .LifestyleSingleton(),
    Component.For<ICommand>()
        .Named("barCommand")
        .ImplementedBy<BarCommand>()
        .LifestyleSingleton());

【问题讨论】:

  • 所以你想在SomeControllerBarCommand 中注入FooCommandHelloController 中?但是如果你交换依赖关系,那些控制器会发生什么,即将BarCommand注入SomeController?这会破坏SomeController 还是会继续正常运行?
  • 这会破坏它,因为它们最终都会与不同的基础表进行对话。
  • 在这种情况下,您违反了Liskov Substitution Principle,这就是您问题的根源。要解决此问题,请为这两个命令提供自己独特的界面。
  • 您可能还想看看使用更多消息驱动的设计,例如this one
  • 现实世界中,它只是对某个表执行 SQL 命令。 @Steven 我不太同意您的方法,因为这意味着我将拥有两个相同的接口。这只是一个不同的实现。您的方法意味着每个具体实现都有一个接口。

标签: c# dependency-injection castle-windsor


【解决方案1】:

就像@steven 说的那样,这通常不是一个好主意,如果管理不当可能会导致可发现性问题,但是假设您知道自己在做什么,您可以构建一个 IContributeComponentModelConstruction 来匹配构造函数参数在具有相同名称的 Windsor 组件的控制器上键入 ICommand

public class ControllerCommandMatcher : IContributeComponentModelConstruction
{
    public void ProcessModel(IKernel kernel, ComponentModel model)
    {
        // or whatever other condition to bail out quickly
        if (model.Implementation.Name.EndsWith("Controller") == false) return;

        foreach (var constructor in model.Constructors)
        {
            foreach (var dependency in constructor.Dependencies)
            {
                if (dependency.TargetItemType != typeof (ICommand)) continue;
                dependency.Parameter = new ParameterModel(dependency.DependencyKey,
                    ReferenceExpressionUtil.BuildReference(dependency.DependencyKey));
            }
        }
    }
}

棘手的一点是:

new ParameterModel(dependency.DependencyKey,
       ReferenceExpressionUtil.BuildReference(dependency.DependencyKey))

它基本上告诉 Windsor 依赖项(构造函数参数),例如 fooCommand 应该满足同名组件 (fooCommand)。

然后将你的贡献者添加到容器中

container.Kernel.ComponentModelBuilder.AddContributor(new ControllerCommandMatcher());

Here's the documentation

【讨论】:

  • 我会试一试并反馈感谢您的帖子。虽然我不明白最后两行代码他们做了什么?它如何知道要注入哪个实例?
猜你喜欢
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多