简体   繁体   English

DI框架如何解决具有多个配置的同一接口的依赖性?

[英]How DI frameworks resolve dependency for same Interface with multiple configuration?

Consider below code sample: 考虑下面的代码示例:

public interface IMyInterface
{
   void SetName(string name);
   string GetName();
}

public class MyInterfaceImplementor1 : IMyInterface
{
   protected string Name { set; get; }

   public void SetName(string name)
   {
      this.Name = name;
   }

   public virtual string GetName()
   {
      return this.Name;
   }
}

public class MyInterfaceImplementor2 : MyInterfaceImplementor1
{
   public override string GetName()
   {
      return String.Format("Hello! {0}", base.Name);
   }
}

And the DI configuration for this: ( StructureMap code snippet provided) 以及为此的DI配置:(提供了StructureMap代码段)

ObjectFactory.Configure(x => 
{
   x.For<IMyInterface>()
    .Use<MyInterfaceImplementor1>();
});

ObjectFactory.Configure(x =>
{
   x.For<IMyInterface>()
    .Use<MyInterfaceImplementor2>();
});  

Say, in my code, at some point I am using MyInterfaceImplementor1 and at some other point, I use MyInterfaceImplementor2 . 说,在我的代码中,有时使用MyInterfaceImplementor1,而有时使用MyInterfaceImplementor2 My question is, how the DI framework (StructureMap or any other) will resolve the above configuration? 我的问题是,DI框架(StructureMap或任何其他框架)将如何解决上述配置? Also, how will it determine, where to return an instance of MyInterfaceImplementor1 and when the same of MyInterfaceImplementor2 ? 另外,它将如何确定在哪里返回MyInterfaceImplementor1的实例以及何时在MyInterfaceImplementor2上返回相同的实例 OR Am I doing something wrong here? 或者我在这里做错了吗?

In your case StructureMap will resolve MyInterfaceImplementor2 . 在您的情况下,StructureMap将解析MyInterfaceImplementor2 StructureMap stores all registrations but resolves the last one registered with Use() method. StructureMap存储所有注册,但解析使用Use()方法注册的最后一个注册。

Nomenclature 命名法

Plugin type - type that is to be injected, in most of the cases it is an interface but SM resolves also concrete types (even if you haven't registered them) 插件类型 -要注入的类型,在大多数情况下,它是一个接口,但是SM还会解析具体的类型(即使您尚未注册它们)

Plugged/concrete type - implementation of plugin type 插入/混凝土类型 -插件类型的实现

c.For<IPluginType>().Use<ConcreteType>();

Generally in SM there are 2 types of manual registration. 通常,在SM中,有2种类型的手动注册。 You can register dependencies with Add() and Use() method. 您可以使用Add()Use()方法注册依赖项。

What is the difference? 有什么区别?

  • Add() just registers concrete type in plugin family Add()只是在插件系列中注册具体类型
  • Use() registers and sets it as default registration to be used when resolving plugin type Use()注册并将其设置为解析插件类型时要使用的默认注册

For Add() there is a convention that when you have only one registration then it will be resolved. 对于Add(),有一个约定,当您只有一个注册时,它将被解析。 In case when there is more than one registration container would throw StructureMapException when trying to resolve plugin type. 如果存在多个注册容器,则在尝试解析插件类型时会抛出StructureMapException

csprabala answer provides good explanation how multiple implementations should be registerd within StructureMap. csprabala答案很好地解释了应如何在StructureMap中注册多个实现。

When I have multiple implementations of plugin type I always register the with Add() method and if there is a default implementation I register it with Use() 当我有多种插件类型的实现时,我总是向Add()方法注册,如果有默认实现,我就向Use()注册它。

How to map same interface to different ConcreteClasses with StructureMap? 如何使用StructureMap将同一接口映射到不同的ConcreteClass?

Look at the above. 看上面。 Most DI frameworks use hints presented in the form of names/attributes to inject the appropriate concrete classes at run time. 大多数DI框架使用以名称/属性形式表示的提示在运行时注入适当的具体类。

Look at the below to 看下面

StructureMap: Choose concrete type of nested dependency StructureMap:选择嵌套依赖项的具体类型

In some cases it makes much sense to have multiple implementations of the same interface, but not in all cases. 在某些情况下,具有同一接口的多个实现非常有意义,但并非在所有情况下都如此。 Always make sure that you are not violating the Liskov Substitution Principle (LSP). 始终确保您没有违反Liskov替代原则 (LSP)。 Here are two cases, one where the use of multiple implementations is okay, and one where it is not. 这有两种情况,一种可以使用多种实现,而另一种则可以。

Say for instance you have an ILogger abstraction with FileLogger and SqlLogger implementations. 假设您有一个ILogger抽象和FileLoggerSqlLogger实现。 In most cases you want to log stuff to the database, but in some parts of the system, you explicitly want to log to a file instead, because the log errors in this part of the system are picked up by a different system that has no access to the database. 在大多数情况下,您希望将内容记录到数据库中,但是在系统的某些部分中,您明确地希望记录到文件中,因为该系统这部分中的日志错误是由没有访问数据库。 Although you should always ask yourself whether or not you're logging too much , as long as swapping the implementations doesn't affect the consumers of the ILogger abstraction, from perspective of the LSP, you are fine. 尽管您应该经常问自己是否记录过多日志 ,但是只要交换实现不会影响ILogger抽象的使用者,从LSP的角度来看,您就可以了。

However, let's say your application communicates with two databases, that each have their own schema. 但是,假设您的应用程序与两个数据库通信,每个数据库都有自己的架构。 On top of this you have an IUnitOfWork abstraction, that is used to communicate with the database. 最重要的是,您具有IUnitOfWork抽象,用于与数据库进行通信。 Based on this abstraction you implemented the OrdersUnitOfWork for communicating with the Orders database, and the CrmUnitOfWork to communicate with the CRM database. 在此基础上抽象你实现OrdersUnitOfWork与订单数据库通信,以及CrmUnitOfWork与CRM数据库进行通信。 Obviously some parts of the system need to get the OrdersUnitOfWork to work, while others need the CrmUnitOfWork . 显然,系统的某些部分需要使OrdersUnitOfWork起作用,而其他部分则需要CrmUnitOfWork If this is the case, you are breaking the LSP, since you can't simply swap the implementations without the consumers to notice. 在这种情况下,您将破坏LSP,因为您不能在没有使用者注意的情况下简单地交换实现。 No, when supplying a consumer with the wrong implementation it will completely break, because the database schema's are completely different. 不可以,当为消费者提供错误的实现时,它将完全中断,因为数据库架构的完全不同。 This is a violation of the LSP. 这违反了LSP。

So in the latter case, the problem is in the design of the application and can be fixed by giving each database its own abstraction. 因此,在后一种情况下,问题出在应用程序的设计中,可以通过为每个数据库提供自己的抽象来解决。 For instance: IOrdersUnitOfWork and ICrmUnitOfWork . 例如: IOrdersUnitOfWorkICrmUnitOfWork

If you do this kind of registration, it completely depends on the DI library you use, whether it returns the first or the last. 如果执行这种注册,则它完全取决于您使用的DI库,无论它返回第一个还是最后一个。 This is often very unintuitive, and this makes it very easy to make a configuration error because of this. 这通常是很不直观的,因此,很容易造成配置错误。

For that reason, the DI library Simple Injector does not allow these kind of registrations. 因此,DI库Simple Injector不允许进行此类注册。 The designers of Simple Injector find such API a design flaw as we explain here . 正如我们在此处解释的那样,Simple Injector的设计人员发现此类API是设计缺陷。 Instead, Simple Injector forces you to make either a single registration for a given key ( IMyInterface in your case) or register a collection of things. 相反,Simple Injector会强制您为给定密钥(在您的情况下为IMyInterface )进行一次注册或注册事物的集合。 This prevents the confusion all together of what the library will return for you. 这样可以避免将库返回给您的所有混淆。

In case you need to determine the implementation to inject, based on its consumer, Simple Injector allows you to do context based injection . 万一您需要根据其使用者确定要注入的实现,Simple Injector允许您进行基于上下文的注入 For instance: 例如:

container.Register<MyInterfaceImplementor1>();
container.Register<MyInterfaceImplementor2>();

container.RegisterWithContext<IMyInterface>(context =>
    context.ImplementationType.Namespace.Contains("Administrator")
        ? container.GetInstance<MyInterfaceImplementor1>()
        : container.GetInstance<MyInterfaceImplementor2>());

Here which implementation to inject is determined based on the namespace of the consumer. 在此,根据使用者的名称空间确定要注入的实现。 You can think of all kind of rules of course to determine what to inject. 您当然可以考虑各种规则来确定要注入的内容。

StructureMap will blow up with an exception because it will NOT try to guess which one you want if there's more than one registration -- and I stand by that decision to this day. 如果有多个注册,StructureMap会发生异常,因为它不会尝试猜测您想要哪个注册-我一直坚持这一决定。 Some of the other IoC containers will use either the first one registered or the last one registered. 其他一些IoC容器将使用第一个注册的容器或最后一个注册的容器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在StructureMap DI和MVC 5中解析相同类型的多个实现 - How to resolve multiple implementations of the same type in StructureMap DI and MVC 5 如何使用 .NET CORE DI 为同一接口注册多个实现 - How to register multiple implementation for same interface using .NET CORE DI IoC / DI:当存在同一接口的多个实现时,如何注入特定实例 - IoC/DI: How to inject specific instance when there are multiple implementations of same interface 如何使用采用同一接口的两个实现的类构造函数解决依赖注入 - How to resolve dependency injection with class constructor that takes two implementations of the same interface 如何在没有条件/上下文DI的情况下将不同的实现注入相同的接口? - How to inject different implementations to same interface without conditional/context DI? Unity DI-使用构造函数解析接口 - Unity DI - resolve interface using constructor 如何针对同一版本将多个.net框架作为目标 - How to target multiple .net frameworks for same build 在单个接口上实现DI多重实现 - DI multiple implementation on single interface 一个接口与 DI 的多种实现 - Multiple implementations for one interface with DI 依赖注入-当实现使用Unity for DI时如何使用简单注入器注入接口实现 - Dependency Injection - How to inject implementation of interface using Simple Injector when the implementation uses Unity for DI
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM