C# 具有两个实现相同接口的类的IOC/DI
我对两个类实现相同接口和依赖注入的场景感到困惑C# 具有两个实现相同接口的类的IOC/DI,c#,.net,design-patterns,dependency-injection,inversion-of-control,C#,.net,Design Patterns,Dependency Injection,Inversion Of Control,我对两个类实现相同接口和依赖注入的场景感到困惑 public interface ISomething { void DoSomething(); } public class SomethingA : ISomething { public void DoSomething() { } } public class SomethingAB : ISomething { public void DoSomething() { } } public class
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;
}
}
我在网上看到过一些例子,说这是有效的,但是你一次只能使用一个类。因此,如果应用程序在SiteA上运行,你会告诉你的IOC使用某些东西A,但如果应用程序在SiteB上运行,你会告诉它使用某些东西B
因此,让一个应用程序有两个类来实现一个接口并尝试同时使用这两个类,这被认为是不好的做法吗?如果不是,你如何告诉国际奥委会在相关情况下使用哪个级别
更新:为了更好地解释它,我将使用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
}
}
公共级武士
{
私人武器;
公共武士(IWeapon武器)
{
这个。武器=武器;
}
}
公共级剑:IWeapon
{
...
}
公共级枪:IWeapon
{
...
}
公共类WarriorModule:NinjectModule
{
公共覆盖无效负载()
{
this.Bind().To();
this.Bind().To();//只是一个例子
}
}
现在有两个类使用IWeapon。根据应用程序中的某些内容或上下文,您希望武士有时拥有一把剑,或者在其他地方拥有一把枪。你是如何做到这一点的?你如何处理这种“如果”的情况???在这种情况下,我与Unity和spring合作,我认为兴趣在于在包(即类)之间具有弱耦合,改变服务或入口点的能力是国际奥委会的结果 ioc提供服务使用的灵活性,或从服务实现相同接口时起 如果使用服务A,服务B和服务在服务包A中,包B在B中。 包A在包b上没有引用,但服务A在包含接口的包上有引用。
因此,我们得出结论,在包a和包b之间存在弱耦合。我不认为这在一般情况下是一种不好的做法。在某些情况下,您可能需要在同一应用程序中使用同一接口的不同实现,并根据上下文使用一个或另一个实现 至于如何配置您的DI以启用此场景,当然,这将取决于您的DI:-)一些可能不支持它,其他可能不支持,其他可能部分支持它,等等 例如,您可以使用以下类:
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);
}
}
然后在配置内核时使用命名绑定:
// 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")
);
将多个实现映射到同一个接口并不是很糟糕的做法,但这不是最常见的使用模式
您没有指定特定的DI工具,但如果使用Unity,则可以对命名实例执行此操作。请参阅:个人不会认为这是一个糟糕的实践-它是一个主要的点定义接口首先!至于如何让你的IOC容器支持这一点,这在很大程度上取决于IOC,我使用的所有容器都支持各种条件配置选项。添加一个具体的国际奥委会来得到答案。问题的存在并不是具体的国际奥委会,而是我的理解。我假设自己实例化类不是最佳实践,如果可以的话,我假设我需要使我的IOC在全球可见,以获得正确的实例,我也不确定这是否是最佳实践。IOC的一般“最佳实践”是只在一个地方拥有它。也有例外,但这是经验法则。不过,其中一个例外情况是,您需要这种运行时配置—假设您有一个事件,该事件创建了一个需要可配置依赖项的类,您可以在该事件的处理程序(IMO)中引用您的IOC。一个全局可见的IOC是一个大的反模式(服务定位器)。关于一个具体的例子,请参见Darin的回答:)是否创建了两个类来接受不必要的重复代码?所有这些都是在程序开始时完成的,但这可能只是一个学习曲线,但我假设我将不再在代码中实例化类??我不明白为什么这会是重复的代码。您可能有两个类需要相同的契约(ISomething),这些类的使用者根据上下文决定需要注入不同的实现。此外,我不会在应用程序中请求Foo或Bar的实例,因为我需要使内核全局可见??不,您永远不会这样做。内核应该是绝对透明的。您不应该在消费代码中直接使用它。例如,在ASP.NET MVC中,您可以使用带有NInject(NInject.MVC3 NuGet)的自定义DependencyResolver,它将直接将您指示的依赖项注入控制器。在99%的应用程序中,您从不编写诸如
kernel.Get()
之类的代码。您永远不需要访问内核。您可以在应用程序的生命周期内配置一次,然后让它完成它的工作。谢谢。我不知道在现阶段,这种情况可能是什么,我只是想学习,但我意识到在某些时候,会/必须有两个类实现同一个接口的场景,所以必须有一种方法告诉程序使用一个或另一个基于某个东西的类…不管是什么。接口的多个实现实际上就是为什么在第一名。让我们不要用哑DI框架的pupets来考虑接口。OP问“这被认为是不好的做法吗”,我回答“将多个实现映射到同一个接口并不是真正的坏做法”。。。我们同意,而你却对我投了反对票?你说“这不是最常见的使用模式”,而事实上,这是非常普遍的。为类编写接口是为了编写接口而不是在其他地方重用它吗?
var foo = kernel.Get<Foo>();
var bar = kernel.Get<Bar>();