【问题标题】:IoC/DI: How to inject specific instance when there are multiple implementations of same interfaceIoC/DI:当同一接口有多个实现时如何注入特定实例
【发布时间】:2016-03-01 20:16:11
【问题描述】:

假设我们有两个IService 接口的实现:

public interface IService { }

public class Service1 : IService { }

public class Service2 : IService { }

那么我们有两个依赖于IService的类:

public class Consumer1
{
    public Consumer1(IService svc) { }
}

public class Consumer2
{
    public Consumer2(IService svc) { }
}

现在,我怎样才能将Service1 注入Consumer1Service2 注入Consumer2,使用Simple Injector 作为依赖容器并且不使用 使用工厂或单独的接口?

如何存档的通用模式(与特定 DI 容器无关)也很棒:)

更新
我已经尝试过使用 Simple Injector 进行基于上下文的注入。文档非常有限,我最终得到以下代码:

container.RegisterConditional(
    typeof(IService),
    typeof(Service1),
    Lifestyle.Transient,
    c => c.Consumer.ImplementationType == typeof(Consumer1));

container.RegisterConditional(
    typeof(IService),
    typeof(Service2),
    Lifestyle.Transient,
    c => c.Consumer.ImplementationType == typeof(Consumer2));

container.Register<Consumer1>();
container.Register<Consumer2>();

然后我得到一个异常

配置无效。为 Consumer1 类型创建实例失败。 Consumer1 类型的构造函数包含名为“svc”的参数和未注册的 IService 类型。请确保 IService 已注册,或更改 Consumer1 的构造函数。存在 1 个适用于 IService 的 IService 条件注册,但其提供的谓词在提供 Consumer1 的上下文信息时未返回 true。

我尝试了不同的谓词变体,但没有成功......

c => c.Consumer.Target.TargetType == typeof(Consumer1)
c => c.Consumer.ServiceType == typeof(Consumer1)

【问题讨论】:

  • 答案总是特定于您使用的 DI 框架。您正在询问“基于上下文的注入”,对于 SimpleInjector,它已记录在 here 中。由于您对其他 DI 框架感兴趣,Ninject 喜欢 this
  • 你碰巧有几个同名的接口IService
  • “不使用...单独的接口”。确保您没有违反此处的Liskov Substitution Principle,因为如果您这样做,答案通常实际上是 is* 以创建单独的接口。
  • 请注意,PredicateContextConsumer 属性描述了“当前依赖项的消费类”(或父级),而 Consumer.Target 描述了依赖项的构造函数参数或属性注入。所以Consumer.Target.TargetType 将(几乎)始终等于注册类型(在您的情况下为IService)。 Consumer.Target 对于获取属性或参数名称更有用,也可用于查询某些属性。

标签: c# dependency-injection inversion-of-control simple-injector


【解决方案1】:

我无法使用最新版本 (3.1) 的 SI 重现此问题。此测试通过:

[Test]
public void Test1()
{
    var container = new Container();

    container.RegisterConditional<IService, Service1>(
        c => c.Consumer.ImplementationType == typeof(Consumer1));
    container.RegisterConditional<IService, Service2>(
        c => c.Consumer.ImplementationType == typeof(Consumer2));
    container.Register<Consumer1>();
    container.Register<Consumer2>();

    container.Verify();

    var result1 = container.GetInstance<Consumer1>();
    var result2 = container.GetInstance<Consumer2>();

    Assert.IsInstanceOf<Service1>(result1.Svc);
    Assert.IsInstanceOf<Service2>(result2.Svc);
}

您使用的是哪个版本的 SI,您确定您使用的是正确的 container 实例吗?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-13
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    • 2013-04-03
    • 2019-05-27
    相关资源
    最近更新 更多