IOC/DI有2个实现相同接口的类

Jon*_*Jon 10 .net c# design-patterns dependency-injection inversion-of-control

我对实现相同接口和依赖注入的2个类的场景感到困惑.

public interface ISomething
{
  void DoSomething();
}

public class SomethingA : ISomething
{
  public void DoSomething()
  {

  }
}

public class SomethingAB : ISomething
{
  public void DoSomething()
  {

  }
}

public class Different
{
  private ISomething ThisSomething;

  public Different(ISomething Something)
  {  
    ThisSomething = Something;
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经看到在线示例说这是有效的,但你一次只能使用一个类.因此,如果应用程序在SiteA运行,您告诉您的IOC使用SomethingA,但如果它在SiteB,您告诉它使用SomethingAB.

因此,有一个应用程序有2个类实现1个接口,并尝试使用这两个类,这被认为是不好的做法吗?如果不是你怎么告诉国际奥委会在相关情况下使用哪个班级?

更新:为了更好地解释它,我将使用Ninject的例子:

public class Samurai 
{
    private IWeapon Weapon;

    public Samurai(IWeapon weapon) 
    {
        this.Weapon = weapon;
    }
}

public class Sword : IWeapon
{
...
}

public class Gun : IWeapon
{
...
}

public class WarriorModule : NinjectModule
{
    public override void Load() 
    {
        this.Bind<IWeapon>().To<Sword>();
        this.Bind<IWeapon>().To<Gun>();  //Just an example
    }
}
Run Code Online (Sandbox Code Playgroud)

所以现在你有两个使用IWeapon的类.根据您应用中的某些内容或背景,您希望Samurai有时会使用剑或在其他点使用枪.你是怎么做到这一点的?你如何处理"if"场景?

Dar*_*rov 13

我不认为这在一般情况下是不好的做法.在某些情况下,您可能需要在同一个应用程序中使用相同接口的不同实现,并且基于上下文使用一个或另一个实现

至于如何配置你的DI以启用这个场景,当然,它将取决于你的DI :-)有些人可能不支持它,其他人可能不支持,其他人可能部分支持它等等.

例如,使用Ninject,您可以拥有以下类:

public interface ISomething
{
}

public class SomethingA : ISomething
{
}

public class SomethingB : ISomething
{
}

public class Foo
{
    public Foo(ISomething something)
    {
        Console.WriteLine(something);
    }
}

public class Bar
{
    public Bar(ISomething something)
    {
        Console.WriteLine(something);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在配置内核时使用命名绑定:

// We create the kernel that will be used to provide instances when required
var kernel = new StandardKernel();

// Declare 2 named implementations of the same interface
kernel.Bind<ISomething>().To<SomethingA>().Named("somethingA");
kernel.Bind<ISomething>().To<SomethingB>().Named("somethingB");

// inject SomethingA into Foo's constructor
kernel.Bind<Foo>().ToSelf().WithConstructorArgument(
    "something", ctx => ctx.Kernel.Get<ISomething>("somethingA")
);

// inject SomethingB into Bar's constructor
kernel.Bind<Bar>().ToSelf().WithConstructorArgument(
    "something", ctx => ctx.Kernel.Get<ISomething>("somethingB")
);
Run Code Online (Sandbox Code Playgroud)

现在当你请求Foo它的一个实例时,它会SomethingA向它注入它的构造函数,当你请求Bar它的实例时会注入SomethingB它:

var foo = kernel.Get<Foo>();
var bar = kernel.Get<Bar>();
Run Code Online (Sandbox Code Playgroud)

  • 不,你永远不会这样做.内核应该绝对透明.您永远不应该在您的消费者代码中直接使用它.例如,在ASP.NET MVC中,您可以使用带有NInject(Ninject.MVC3 NuGet)的自定义DependencyResolver,它只会将您指定的依赖项直接注入控制器.在99%的应用程序中,您永远不会编写诸如`kernel.Get <Something>()`之类的代码.您永远不需要访问内核.您可以在应用程序的生命周期内对其进行一次配置,并使其完成工作. (2认同)