.net core Dotnet核心依赖注入,如何注册同一类的多个实例

.net core Dotnet核心依赖注入,如何注册同一类的多个实例,.net-core,dependency-injection,.net Core,Dependency Injection,我想知道是否可以使用内置的dotnet core DI框架注册同一类的多个实例 例如,我有一个类ToDo,它向客户端发送消息。我想要两个相同ToDo对象的实例,它们具有不同的注入配置对象。最后,我将有两个独立的ToDo对象实例 这可能吗 编辑: 假设我有一个模式pub/sub 我有一个名为MessageSubService.cs的泛型类,其实现如下所示 public class ASBMessageSubService : ASBSubService, IASBSubService {

我想知道是否可以使用内置的dotnet core DI框架注册同一类的多个实例

例如,我有一个类
ToDo
,它向客户端发送消息。我想要两个相同
ToDo
对象的实例,它们具有不同的注入配置对象。最后,我将有两个独立的
ToDo
对象实例

这可能吗


编辑:

假设我有一个模式
pub/sub

我有一个名为
MessageSubService.cs
的泛型类,其实现如下所示

public class ASBMessageSubService : ASBSubService, IASBSubService
{
       public ASBMessageSubService(..., IOptions<ASBSubOptions> options): base(options)
}
这将为我注册3个不同的实例。问题是实现是相同的,我无法通过where`nameof(ASBMessageSubService)的类型来解决它

我也可以注册一个
deligate
,在那里我可以根据名称或类型来解决它,但这遇到了我上面描述的相同问题,实现的类型将是相同的

(我知道我可以使用
structuremap
autofac
等库将它们注册为命名实例来完成这项工作。不过,我希望在本项目中避免使用类似的第三方工具。)

有什么建议吗


谢谢大家!

大卫·G回答了这个问题。我将稍微扩展它以帮助您和其他人

您可以将多个类注册为自身或接口:

services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub1"));
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub2"));
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub3"));

// re-register as IASBSubService
foreach (var service in services.Where(s => s.ServiceType == typeof(ASBMessageSubService)).ToList())
{
    services.AddSingleton<IASBSubService >(provider => service.ImplementationFactory(provider) as IASBSubService );
}

// re-register as ISubService
foreach (var service in services.Where(s => s.ServiceType == typeof(ASBMessageSubService)).ToList())
{
    services.AddSingleton<ISubService>(provider => service.ImplementationFactory(provider) as ISubService);
}
e、 g

services.AddTransient(provider=>newtodo(configuration1));
AddTransient(provider=>newtodo(configuration2));
AddTransient(provider=>newtodo(configuration3));
...
services.AddTransient();
然后对于依赖项注入,对
IEnumberable
进行依赖:

公共类需要做的事情:ITodoWorker
{
公共需求TODO(IEnumerable TODO)
{
foreach(todo中的变量todo)
{
如果(todo.Id==“配置1”)
{
//如果您需要查找特定的Todo实例,那么这是一个好主意
}
}
}
}

如果这不仅仅是编辑错误,那么这个声明可能是错误的:

service.AddSingleton<ASBMessageSubService, IASBSubService>
然后:

如果您所追求的是具体类型,无论是
ASBSubService
还是
ASBMessageSubService
,您都可以使用以下方法获得具体类型:

var sub = subs.SingleOrDefault(x => x.Name.GetType() == typeof(ASBSubService));

// GetType() never returns the interface type (I think) See https://stackoverflow.com/questions/1159906/finding-the-concrete-type-behind-an-interface-instance/1159940

在接口中公开一些东西来帮助您选择实例的类型,这可能是您正在寻找的。这是解决这类问题的常见方法。

这让我有些紧张。我不得不打开DI机械学上的引擎盖:

首先,接口和类:

public interface ISubService {} // just a second interface I made up

public interface IASBSubService {}

public class ASBMessageSubService : IASBSubService, ISubService
{
   public string Name { get; set; }

   public ASBMessageSubService(string name)
   {
       Name = name;
   }
}
现在,我找到了一种将现有已注册实例重新注册为不同接口的方法:

services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub1"));
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub2"));
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub3"));

// re-register as IASBSubService
foreach (var service in services.Where(s => s.ServiceType == typeof(ASBMessageSubService)).ToList())
{
    services.AddSingleton<IASBSubService >(provider => service.ImplementationFactory(provider) as IASBSubService );
}

// re-register as ISubService
foreach (var service in services.Where(s => s.ServiceType == typeof(ASBMessageSubService)).ToList())
{
    services.AddSingleton<ISubService>(provider => service.ImplementationFactory(provider) as ISubService);
}
services.AddSingleton(provider=>newsubservicessubscriber(“sub1”);
services.AddSingleton(provider=>新的子服务订户(“sub2”);
services.AddSingleton(provider=>新的子服务订户(“sub3”);
//重新注册为IABSubservice
foreach(services.Where(s=>s.ServiceType==typeof(ASBMessageSubService)).ToList()中的var服务)
{
services.AddSingleton(provider=>service.ImplementationFactory(provider)作为IABSubservice);
}
//重新注册为ISubService
foreach(services.Where(s=>s.ServiceType==typeof(ASBMessageSubService)).ToList()中的var服务)
{
services.AddSingleton(provider=>service.ImplementationFactory(provider)作为ISubService);
}
然后对所需的接口进行依赖:

public class Subscriptions
{
    public Subscriptions(IEnumerable<IASBSubService> subs)
    { ... }
}
公共类订阅
{
公共订阅(IEnumerable subs)
{ ... }
}

公共类服务管理器
{
公共服务经理(IEnumerable subs)
{ ... }
}

如果有更干净的方法,其他人需要告诉我。

您多次调用
服务。AddSingleton(…)
您的消费者类可以使用
IEnumerable
作为示例。@DavidG谢谢。我知道这种做法。然而,我的服务是单例的,这个例子让我感到困惑的是,一旦我注入
IEnumerable
我怎么知道要得到什么实例,因为下面的实现是相同的?例如,我将为每个
IToDo
接口注册相同的
ToDoService
多次?如果您需要更详细的DI,一定要查看Scrutor()谢谢,这个解决方案的问题是,
todo.Id
将无法访问,因为它也将由DI提供,并且在每个实现中都是
私有只读的。我想我需要的是一个
NamedInstance
,以便能够通过nameOK解析服务。如果你需要进一步的帮助,你必须提供一个真实的例子。我只需要像上面那样使用
Id
方法,或者我只需要处理每个
Todo
(即,不挑出一个实例)更新问题。如果不需要,请发现我不一致。当然,接口不必是
Name
。它可以是您选择的任何类型的鉴别器。您可以返回
Type
并以这种方式公开底层类型。在界面中公开一些东西来帮助您选择您要查找的实例类型。谢谢。同样,这会让我暴露不需要的属性,只是为了解决依赖关系。如果团队的其他成员将使用此API,我认为这不会很好地扩展,因为他们必须为每个实现提供名称。谢谢你的解决方案和想法……你需要一个鉴别器。你的鉴别器是什么?它是实现类的类型吗?我在这些行中寻找一些东西:这允许您注册一个命名实例,并能够在解析时按名称解析它。我不确定在dotnetdi框架中是否有类似的事情可以做到。
public interface IASBSubService
{
    string Name { get; }
    ...
}
public class ASBMessageSubService : IASBSubService, ...
{
    public string Name { get; private set; }

    public ASBMessageSubService(..., IOptions<ASBSubOptions> options)
    {
        Name = options.Value.SubscriberName;
        ...
    }
}
public class Subscribers
{
    public Subscribers(IEnumerable<IASBSubService> subs)
    {
        var sub = subs.SingleOrDefault(x => x.Name == "Service1");
    }
}
var sub = subs.SingleOrDefault(x => x.Name.GetType() == typeof(ASBSubService));

// GetType() never returns the interface type (I think) See https://stackoverflow.com/questions/1159906/finding-the-concrete-type-behind-an-interface-instance/1159940
public interface ISubService {} // just a second interface I made up

public interface IASBSubService {}

public class ASBMessageSubService : IASBSubService, ISubService
{
   public string Name { get; set; }

   public ASBMessageSubService(string name)
   {
       Name = name;
   }
}
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub1"));
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub2"));
services.AddSingleton<ASBMessageSubService>(provider => new SubServiceSubscriber("sub3"));

// re-register as IASBSubService
foreach (var service in services.Where(s => s.ServiceType == typeof(ASBMessageSubService)).ToList())
{
    services.AddSingleton<IASBSubService >(provider => service.ImplementationFactory(provider) as IASBSubService );
}

// re-register as ISubService
foreach (var service in services.Where(s => s.ServiceType == typeof(ASBMessageSubService)).ToList())
{
    services.AddSingleton<ISubService>(provider => service.ImplementationFactory(provider) as ISubService);
}
public class Subscriptions
{
    public Subscriptions(IEnumerable<IASBSubService> subs)
    { ... }
}
public class ServiceManager
{
    public ServiceManager(IEnumerable<ISubService> subs)
    { ... }
}