IoC – 多个实现支持单个接口

我想知道为什么.Net IoC容器不能轻易支持单个接口的多个实现! 可能是我错了,但就我所见,像Ninject这样的框架部分支持使用注释这个function( 如何? )。 我不认为像Windsor或简单注入器这样的其他框架有一个简单的机制来支持这种情况。

是否有任何理由不支持许多框架? AFAIK,使用接口的最重要原因之一是实现松散耦合。 如果框架旨在改善松耦合,不能流利地支持单个接口的多个实现,我不明白为什么!

PS当然我理解在运行时会出现解决问题,容器会混淆选择哪种实现,但这是设计中必须考虑的事情,对吧?

Unity具有相同的function

注册命名依赖项

  var container = new UnityContainer(); container.RegisterType("TestConnector"); 

按名称解析

  container.Resolve("TestConnector"); 

同样的方法

  [Dependency("TestConnector")] public IConnector Connector { get; set; } 

温莎也一样

 class Program { static void Main(string[] args) { var container = new WindsorContainer() .Register(Component.For().ImplementedBy().Named("ConnectorA")) .Register(Component.For().ImplementedBy().Named("ConnectorB")); var connectorA = container.Resolve("ConnectorA"); Console.WriteLine("Connector type: {0}", connectorA.GetType()); var connectorB = container.Resolve("ConnectorB"); Console.WriteLine("Connector type: {0}", connectorB.GetType()); Console.ReadKey(); } } public interface IConnector { } public class ConnectorA : IConnector { } public class ConnectorB : IConnector { } 

我建议查看约定优于配置 ,特别是基于约定的dependency injection基于 上下文的dependency injection。 大多数IoC(如果不是全部)都支持这两种方法。 当几个实现绑定到一个接口时,您可以找到许多具有不同IoC库的有趣示例,以及它可能有多大用处。

例如, ninject支持绑定一个接口的多个实现:依赖于上下文或属性,按名称等等 。

按上下文

以下片段绑定实现取决于目标类型自动:

 Bind().To().WhenInjectedInto(typeof(OnLandAttack)); Bind().To().WhenInjectedInto(typeof(AmphibiousAttack)); 

按名字

配置在XML或数据库中时非常有用。 考虑到InNamedScope

 Bind().To().Named("Strong"); Bind().To().Named("Weak"); 

按惯例

在项目的不同部分使用不同的依赖关系配置。

你的前提是错的。

温莎非常高兴地接受同一服务的多个实现的注册。 除了GSerjo在Windsor中提到的命名组件解析支持(默认情况下),第一个注册的实现将获胜但您可以在注册替代实现时使用IsDefault()方法来覆盖它。 有关更多详细信息,请参阅http://docs.castleproject.org/Windsor.Registering-components-one-by-one.ashx 。

如果您希望对多个实现中的选择进行更多控制,可以创建一个IHandlerSelector实现来执行此操作。 有关详细信息,请参阅http://stw.castleproject.org/Windsor.Handler-Selectors.ashx 。

我的容器Griffin.Container支持它。

 registrar.RegisterConcrete(); registrar.RegisterConcrete(); 

并获取:

 var services = container.Resolve(); 

但是,您无法获得一个特定的实现。 这是一个设计决定。 如果必须获得特定的实现,在容器中注册工厂要好得多。 在最佳实践部分阅读更多内容。

Griffin.Container可以在github找到: https : //github.com/jgauffin/griffin.container

StructureMap提供以下function:

 For().Add().Named("MyInterfaceImpl1"); For().Add().Ctor().Is(i => i.GetInstance("MyInterfaceImpl1")); 

你的问题有点模糊,因为你没有提供一个具体的例子,说明你何时需要这个。 在大多数情况下,您的应用程序或设计存在问题,或者您没有遵循DI最佳实践。

所有容器都允许您使用与IEnumerable相同的接口注册多个依赖IEnumerable ,即使它们没有对多个实例的深度支持。 然而,将服务列表注入其他服务是一种设计气味,最好将此列表隐藏在Composite之后。 这隐藏了抽象背后有多个实现的事实,并允许您通过仅更改应用程序中的单个位置来轻松更改这些实现的使用方式。 我不相信任何IoC框架都支持为您生成合成,因为没有一种默认的方法来处理包装的实现。 你必须自己写这个复合材料。 但是,由于编写这样的复合实际上非常简单,这certificate在框架中没有这样的特性。

如果您想要多个实现,但总是需要返回一个,基于某些配置,总会有这样做的方法。 大多数容器允许您在XML配置文件中配置这些依赖项。 但即使容器不包含此类function,也可以手动从配置文件中读取该值并在容器中注册正确的类型。

如果您有一个用于生产的特定接口的实现和另一个用于unit testing的实现,那么您应该只在容器中注册生产实现。 您的unit testing应该清除任何DI容器,并且您应该手动创建一个被测试的类,并在其构造函数中注入假依赖项,只需new类型即可。 使用DI容器,污染并使测试复杂化。 要实现此目的,您需要围绕构造函数注入模式设计此类型。 不要在被测服务中调用容器(或容器上的任何其他外观)来检索依赖项。