简体   繁体   English

如何使用采用同一接口的两个实现的类构造函数解决依赖注入

[英]How to resolve dependency injection with class constructor that takes two implementations of the same interface

I only know basics of IoC.我只知道 IoC 的基础知识。 For the sake of simplicity (uhh), I want to stay with Microsoft.Extensions.DependencyInjection .为了简单起见(呃),我想继续使用Microsoft.Extensions.DependencyInjection

The IProcessor interface (and IData one which I don't detail and is implemented by Excel and SQLServer classes): IProcessor接口(和IData接口,我没有详细说明,由ExcelSQLServer类实现):

public interface IProcessor
{
    List<FielModel> ReadFieldsFromExcel();
    List<FieldModel> ReadFieldsFromSQLServer();
}

The Processor implementation: Processor实现:

public class Processor : IProcessor
{
    private readonly IData _excel;
    private readonly IData _sqlServer;
    
    public Processor(IData excel, IData sqlServer)
    {
        _excel = excel;
        _sqlServer = sqlServer;
    }
    
    public List<FielModel> ReadFieldsFromExcel();
    {
        // ..
    }
    
    public List<FieldModel> ReadFieldsFromSQLServer();
    {
        // ..
    }
}

The main Program with the DI.主要Program与DI。

class Program
{
    private static ServiceProvider _serviceProvider;
    
    static void Main(string[] args)
    {
        RegisterServices();
        
        var processor = _serviceProvider.GetService<IProcessor>();
        
        // ..
    }
    
    private static void RegisterServices()
    {
        // Setups dependency injection
        var service = new ServiceCollection()
            .AddSingleton<IProcessor, Processor>()
            .AddSingleton<IData, Excel>()
            .AddSingleton<IData, SQLServer>()
            .AddSingleton<Program>();
            
        _serviceProvider = service.BuildServiceProvider();
    }
}

The problem is that both excel and slqServer are instantiated to SQLServer (ie the last IData registered singleton).问题是excelslqServer都被实例化为SQLServer (即最后一个IData注册的单例)。 How can I resolve this instatiation via dependency injection?如何通过依赖注入解决此实例化问题?

I already found a way to instantiate specific class the following way, but I don't think it is directly (and implicitly) applicable to a class constructor...我已经找到了一种通过以下方式实例化特定类的方法,但我不认为它直接(和隐式)适用于类构造函数......

var excel = _serviceProvider.GetServices<IData>()
                            .First(o => o.GetType() == typeof(Excel));

Thanks for any insights.感谢您提供任何见解。

You could register a delegate:您可以注册一个代表:

var service = new ServiceCollection()
    .AddSingleton<Excel>()
    .AddSingleton<SQLServer>()
    .AddSingleton<IProcessor>(provider =>
        new Processor(
            provider.GetRequiredService<Excel>(),
            provider.GetRequiredService<SQLServer>())
    .AddSingleton<Program>();
        

The simplest way is to declare a marker interface for each specific implementation:最简单的方法是为每个特定实现声明一个标记接口:

public interface IExcelData : IData { /* nothing */ }

public class Excel : IExcelData { ... }

public interface ISqlServerData : IData { /* nothing */ }

public class SqlServer : ISqlServerData { ... }
public class Processor : IProcessor
{
    private readonly IData _excel;
    private readonly IData _sqlServer;
    
    public Processor(IExcelData excel, ISqlServerData sqlServer)
    {
        _excel = excel;
        _sqlServer = sqlServer;
    }

    ...
}
services
    .AddSingleton<IExcelData, Excel>()
    .AddSingleton<ISqlServerData, SQLServer>()
    ...

BTW, instead of manually creating the dependency containers, you should look into using the generic host: https://docs.microsoft.com/en-us/dotnet/core/extensions/generic-host顺便说一句,您应该考虑使用通用主机,而不是手动创建依赖项容器: https : //docs.microsoft.com/en-us/dotnet/core/extensions/generic-host

You could also inject an IEnumerable<YourDependency> if the two concrete types are registered against the same interface.如果两个具体类型是针对同一接口注册的,您还可以注入IEnumerable<YourDependency>

public class Processor : IProcessor
{
    private readonly IEnumerable<IData> _dataDependencies;
    
    public Processor(IEnumerable<IData> dataDependencies)
    {
        _dataDependencies= dataDependencies;
    }
}

You could then resolve the relevant type by having some sort of Enum on the implementing class that you can use to select the appropriate service.然后,您可以通过在实现类上使用某种 Enum 来解析相关类型,您可以使用它来选择适当的服务。 I will use a simple string example to illustrate.我将使用一个简单的字符串示例来说明。 (you probably shouldn't do it this way) (你可能不应该这样做)

public class Processor : IProcessor
{
    private readonly IEnumerable<IData> _dataDependencies;
    
    public Processor(IEnumerable<IData> dataDependencies)
    {
        var selectedDependency = dataDependencies.FirstOrDefault(dep => dep.Type == "Excel");
    }
}

Please try this.请试试这个。

var excel = _serviceProvider.GetServices<Excel.IData>();
                        

After reading comment .看完评论。

You can change constructor as following.您可以按如下方式更改构造函数。

 public Processor(Excel.IData excel, SQLServer.IData sqlServer)
    {
        _excel = excel;
        _sqlServer = sqlServer;
    }

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

相关问题 如何使用带有构造函数参数的类注册依赖注入 - How to register a dependency injection with a class which takes constructor parameters .NET Core 依赖注入 - 解析接口的实现和 IEnumerable - .NET Core Dependency Injection - Resolve implementations and IEnumerable of interface Unity:使用一个接口的两种实现来解析类 - Unity: resolve class with two implementations of one interface 依赖注入和接口的许多实现 - Dependency injection and many implementations of interface 传递Controller构造函数中的接口或类以进行依赖项注入 - Pass Interface or Class in Controller Constructor for dependency injection C# 依赖注入 - 注入采用相同接口作为参数的接口 - C# Dependency Injection - injecting interface that takes the same interface as a parameter 接口如何在构造函数依赖注入中发挥作用 - How Interface play role in Constructor Dependency Injection 如果构造函数采用另一个接口,如何在Simple Injector中进行构造函数注入? - How to do constructor injection in Simple Injector if constructor takes another interface? 如何注册两个实现,然后在.Net Core依赖注入中获得一个 - How to register two implementations then get one in .Net Core dependency injection 依赖注入非接口构造函数 - Dependency Injection non interface constructor
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM