簡體   English   中英

如何使用采用同一接口的兩個實現的類構造函數解決依賴注入

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

我只知道 IoC 的基礎知識。 為了簡單起見(呃),我想繼續使用Microsoft.Extensions.DependencyInjection

IProcessor接口(和IData接口,我沒有詳細說明,由ExcelSQLServer類實現):

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

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();
    {
        // ..
    }
}

主要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();
    }
}

問題是excelslqServer都被實例化為SQLServer (即最后一個IData注冊的單例)。 如何通過依賴注入解決此實例化問題?

我已經找到了一種通過以下方式實例化特定類的方法,但我不認為它直接(和隱式)適用於類構造函數......

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

感謝您提供任何見解。

您可以注冊一個代表:

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

最簡單的方法是為每個特定實現聲明一個標記接口:

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>()
    ...

順便說一句,您應該考慮使用通用主機,而不是手動創建依賴項容器: https : //docs.microsoft.com/en-us/dotnet/core/extensions/generic-host

如果兩個具體類型是針對同一接口注冊的,您還可以注入IEnumerable<YourDependency>

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

然后,您可以通過在實現類上使用某種 Enum 來解析相關類型,您可以使用它來選擇適當的服務。 我將使用一個簡單的字符串示例來說明。 (你可能不應該這樣做)

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

請試試這個。

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

看完評論。

您可以按如下方式更改構造函數。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM