带有多个类实现的接口的依赖注入

时间:2012-06-11 15:39:49

标签: asp.net-mvc-3 oop dependency-injection dry

更新:有没有办法实现我在温莎以外的IoC框架中尝试做的事情? Windsor会很好地处理控制器,但不会解决任何其他问题。我确定这是我的错,但是我正在逐字地阅读教程并且对象没有用ctor注入解析,尽管做了寄存器和解析,它们仍然是空的。我已经废弃了我的DI代码并暂时手动注入,因为该项目对时间敏感。希望在截止日期之前完成DI。


我有一个解决方案,它有多个类都实现了相同的接口

举个简单的例子,Interface

public interface IMyInterface {
    string GetString();
    int GetInt();
   ...
}

具体课程

public class MyClassOne : IMyInterface {
    public string GetString() {
        ....
    }
    public int GetInt() {
        ....
    }
}

public class MyClassTwo : IMyInterface {
    public string GetString() {
        ....
    }
    public int GetInt() {
        ....
    }
}

现在,这些类将在需要的地方注入到它们之上的层中,如:

public class HomeController {

    private readonly IMyInterface myInterface;

    public HomeController() {}

    public HomeController(IMyInterface _myInterface) {
        myInterface = _myInterface
    }
    ...
}

public class OtherController {

    private readonly IMyInterface myInterface;

    public OtherController() {}

    public OtherController(IMyInterface _myInterface) {
        myInterface = _myInterface
    }
    ...
}

两个控制器都注入了相同的接口。

在我的IoC中使用适当的具体类来解析这些接口时,如何区分HomeController需要MyClassOneOtherController的实例需要MyClassTwo的实例1}}?

如何将两个不同的具体类绑定到IoC中的同一接口?我不想创建2个不同的界面,因为它打破了DRY规则,无论如何都没有意义。

在温莎城堡,我会有两行:

container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>());
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>());

这不起作用,因为我只会获得MyClassTwo的副本,因为它是最后注册的接口。

就像我说的那样,如果没有为每个具体的界面创建特定的界面,我就无法做到这一点,这样做不仅打破了DRY规则,也打破了基本的OOP。我如何实现这一目标?


根据Mark Polsen的回答进行更新


这是我目前的IoC,.Resolve语句会在哪里出现?我在温莎文档中看不到任何内容

public class Dependency : IDependency {

    private readonly WindsorContainer container = new WindsorContainer();

    private IDependency() {
    }

    public IDependency AddWeb() {
        ...

        container.Register(Component.For<IListItemRepository>().ImplementedBy<ProgramTypeRepository>().Named("ProgramTypeList"));
        container.Register(Component.For<IListItemRepository>().ImplementedBy<IndexTypeRepository>().Named("IndexTypeList"));

        return this;
    }

    public static IDependency Start() {
        return new IDependency();
    }
}

3 个答案:

答案 0 :(得分:7)

我希望你能使用service overrides

实施例

container.Register(
    Component.For<IMyService>()
        .ImplementedBy<MyServiceImpl>()
        .Named("myservice.default"),
    Component.For<IMyService>()
        .ImplementedBy<OtherServiceImpl>()
        .Named("myservice.alternative"),

    Component.For<ProductController>()
        .ServiceOverrides(ServiceOverride.ForKey("myService").Eq("myservice.alternative"))
);

public class ProductController
{
    // Will get a OtherServiceImpl for myService.
    // MyServiceImpl would be given without the service override.
    public ProductController(IMyService myService)
    {
    }
}

答案 1 :(得分:5)

您应该可以使用命名组件注册来完成它。

container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>().Named("One"));
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>().Named("Two"));

然后用

解决它们
kernel.Resolve<IMyInterface>("One");

kernel.Resolve<IMyInterface>("Two");

See: To specify a name for the component

答案 2 :(得分:2)

DI容器通常遵循注册,解析和发布模式。在注册阶段,有两个步骤。第一种是指定您正在进行的映射。第二步是指定管理哪个注入位置的规则。

当我们尝试使用装饰器解决横切问题时,这个问题很常见。在这些情况下,您有多个类(装饰器)实现单个接口。

简而言之,我们需要实现IModelInterceptorsSelector,它允许您编写命令式代码,以决定将哪个Interceptor应用于哪些类型或成员。

Mark Seemann在.Net书中的Dependency Injection一书中详细描述了这一点。查找第9章拦截或搜索上述界面。

我不是这方面的专家,但是正在寻找完全相同的问题,并在上​​面的书中找到了ans。

希望这有帮助。

此致 DEV1