【问题标题】:Ninject - Bind different interfaces implementations to the same classNinject - 将不同的接口实现绑定到同一个类
【发布时间】:2017-01-25 05:53:43
【问题描述】:

我是 DI 的新手(使用 Ninject)并且刚刚开始学习这些概念,但我一直在摸索一段时间才能理解这一点:

假设我在我的程序中对同一个类有不同的用法(以下示例中的ProcessContext)。

在第一堂课(SomeClass):我想将Implement1注入ProcessContext实例。

第二类(SomeOtherClass):我想将Implement2注入ProcessContext实例。

我应该如何使用 Ninject 执行绑定?

public class Implement1 : IAmInterace
{
   public void Method()
   {
   }
}

public class Implement2 : IAmInterace
{
   public void Method()
   {
   }
}

public class ProcessContext : IProcessContext
{
   IAmInterface iamInterface;
   public ProcessContext(IAmInterface iamInterface)
   {
      this.iamInterface = iamInterface;
   } 
}

public class SomeClass : ISomeClass
{
    public void SomeMethod()
    {
        // HERE I WANT TO USE: processcontext instance with Implement1
        IProcessContext pc = kernel.Get<IProcessContext>();            
    }
}

public class SomeOtherClass : ISomeOtherClass
{
    public void SomeMethod()
    {
        // HERE I WANT TO USE: processcontext instance with Implement2
        IProcessContext pc = kernel.Get<IProcessContext>();            
    }
}

【问题讨论】:

  • 听起来您需要像strategy pattern 这样的东西,它允许您根据参数选择实现。这是另一个example,它结合了相同的模式和抽象工厂来动态获取实例。

标签: c# dependency-injection ninject


【解决方案1】:

您可以为此使用named bindings

例如类似:

Bind<IProcessContext>()
    .To<ProcessContext>()
    .WithConstructorArgument("iamInterface", context => Kernel.Get<Implement1>())
    .Named("Imp1");

Bind<IProcessContext>()
    .To<ProcessContext>()
    .WithConstructorArgument("iamInterface", context => Kernel.Get<Implement2>())
    .Named("Imp2");

kernel.Get<IProcessContext>("Imp1");

【讨论】:

  • 谢谢!你能进一步解释一下如何使用 SimpleInjector 吗?
  • @ohadinho 抱歉,我没有任何使用 SimpleInjector 的经验。您应该为该库提出一个新问题。
  • 发现 SimpleInjector 中有一个基于上下文的注入:simpleinjector.readthedocs.io/en/latest/…
  • 这不是一个糟糕的功能,感谢您的分享,因为我也不知道它存在。但我确实觉得它开始稍微削弱使用依赖注入的理由。您允许同一个接口有多个名称,并且可以根据不同的名称将不同的类型注入该接口......但是;在某些时候,DI 开始变得比直接引用类型更易于维护。谁能帮助我了解从长远来看这如何成为更好的选择?在这里张开耳朵。
【解决方案2】:

您可以通过这种方式轻松地注入额外的构造函数参数:

public void SomeMethod()
{
    var foo = new Ninject.Parameters.ConstructorArgument("iamInterface", new Implement2());
    IProcessContext pc = kernel.Get<IProcessContext>(foo);            
}

目前,我无权访问ninject。如果它没有按预期工作,请告诉我。

【讨论】:

  • 在我的示例中,我只使用了 2 个接口。发生了什么“foo”有同样的问题?如果 Implement2 在构造函数中获取 IAmInterface2,我将再次需要设置 ConstructorArgument。没有更简单的方法吗??
  • @ohadinho 在您的情况下,您希望将具体类型传递给IProcessContext。实际上你不想使用 DI 容器。但是如果Implement2 需要一些其他接口作为它的参数,你必须注入所需的参数。我的意思是通常你从Ninject 本身获取你的实例并让Ninject 将参数传递给它。
【解决方案3】:

这是不可能的,因为 Ninject 无法知道返回哪个实现。然而;如果您通过传入一个变量来创建 IProcessContext 的新实例,那么 Ninject 将使用适当的构造函数查找实现并返回该实现。

【讨论】:

    最近更新 更多