.Net Core DI 注入抽象类在派生类中使用接口

Posted

技术标签:

【中文标题】.Net Core DI 注入抽象类在派生类中使用接口【英文标题】:.Net Core DI injection Abstract class using Interface in a derived class 【发布时间】:2021-12-08 23:55:39 【问题描述】:

我有一个派生类,它派生自一个抽象类,而抽象类实现了接口。我想注入抽象类以使用抽象类和接口类的成员。我的课看起来像:

 public interface IStorageTableQueryHelper

    IStorageTableQueryHelper Connect(string storageconnectionString, string entityName);
    Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncStruct<T>(Expression<Func<TableEntity, bool>> expression,
        List<string> selectField) where T : struct;

    Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncStruct<T>(string query, List<string> selectField) where T : struct;
   

我的抽象类

 public abstract class StorageTableQueryAbstractHelper : IStorageTableQueryHelper

    public abstract IStorageTableQueryHelper Connect(string storageconnectionString, string entityName);

    public abstract Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncStruct<T>(
        Expression<Func<TableEntity, bool>> expression, List<string> selectField) where T : struct;


    public abstract Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncClass<T>(Expression<Func<TableEntity, bool>> expression, List<string> selectField) where T : class, new();

    public abstract Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncStruct<T>(string query,
        List<string> selectField) where T : struct;

    public abstract Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncClass<T>(string query,
        List<string> selectField) where T : class, new();


我的派生类

 public class StorageTableQueryHelper : StorageTableQueryAbstractHelper

    private readonly ITableService _tableService;
    private string connectionString  get; set; 
    private string entityName  get; set; 

    public StorageTableQueryHelper(ITableService tableService)
    
        _tableService = tableService;
    

    public override IStorageTableQueryHelper Connect(string storageConnectionString, string entityTableName)
    
        this.connectionString = storageConnectionString;
        this.entityName = entityTableName;
        return this;
    

    public override async  Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncStruct<T>(Expression<Func<TableEntity, bool>> expression, List<string> selectField) where T : struct
    
       //var result= await _tableService.Connect(this.connectionString,this.entityName).ExecuteQuery<T>(expression, selectField);
       return null;
    
    public override async Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncClass<T>(Expression<Func<TableEntity, bool>> expression, List<string> selectField) where T : class
    
      //  var result = await _tableService.Connect(this.connectionString, this.entityName).ExecuteQuery<T>(expression, selectField);
        return null;
    
    public override async Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncStruct<T>(string query, List<string> selectField) where T:struct
    
        //var result = await _tableService.Connect(this.connectionString, this.entityName).ExecuteQuery<T>(query, selectField);
        return null;
    
    public override async Task<ContinuationTokenPageResult<T>> ExecuteTableQueryAsyncClass<T>(string query, List<string> selectField) where T : class
    
       // var result = await _tableService.Connect(this.connectionString, this.entityName).ExecuteQuery<T>(query, selectField);
        return null;
    

还有我想在其中注入基类以使用接口实现的类

 public class EShopBusinessLogicProcessor : IEShopBusinessLogicProcessor

    private readonly IStorageTableQueryHelper _storageTableQueryHelper;
    private  EShopHttpRequestPayload _eShopHttpRequestPayload;

    public EShopBusinessLogicProcessor(IStorageTableQueryHelper storageTableQueryHelper)
    
        _storageTableQueryHelper = storageTableQueryHelper;
    

我正在尝试使用看起来像的 .Net Core DI

   services.AddScoped<IStorageTableQueryHelper, StorageTableQueryAbstractHelper>();
   services.AddScoped<StorageTableQueryHelper>();

但我无法注入它,因为它说接口不包含定义,即使我尝试使用抽象类注入

   public class EShopBusinessLogicProcessor : IEShopBusinessLogicProcessor

    private readonly StorageTableQueryAbstractHelper _storageTableQueryHelper;
    private  EShopHttpRequestPayload _eShopHttpRequestPayload;

    public EShopBusinessLogicProcessor(StorageTableQueryAbstractHelper storageTableQueryHelper)
    
        _storageTableQueryHelper = storageTableQueryHelper;
    

如何实现将抽象类注入消费者类?

【问题讨论】:

您需要注册具体类,而不是抽象类。抽象类不能被实例化。现在你告诉容器在有人请求接口时实例化抽象类 @PanagiotisKanavos 实现接口的 2 个或更多类可以使用键名在 DI 中注册,这不是问题。我想使用从抽象类派生的类作为可以有多个实现的DI 我已经回答你这里没有使用任何键,也没有注册抽象类型。您已经注册了IStorageTableQueryHelper StorageTableQueryHelper。这意味着您不能将其用作依赖项。您必须更改注册或构造函数参数类型 你想做什么?为什么不使用services.AddScoped&lt;IStorageTableQueryHelper, StorageTableQueryHelper&gt;(); 【参考方案1】:

您可以使用回调注册接口并解析其中的抽象类。但是您必须先将抽象类映射到实现。

// map the abstract class to an implementation
services.AddScoped<StorageTableQueryAbstractHelper, StorageTableQueryHelper>();

// then map the interface to abstract class
services.AddScoped<IStorageTableQueryHelper>(sp => sp.GetRequiredService<StorageTableQueryAbstractHelper>());

// or register it directly with the implementation
// services.AddScoped<IStorageTableQueryHelper, StorageTableQueryHelper>();

【讨论】:

这比services.AddScoped&lt;IStorageTableQueryHelper, StorageTableQueryHelper&gt;(); 好在哪里?如果有的话,这会增加出错的机会 @PanagiotisKanavos 正如我在回答中提到的那样,这是一种更直接的方法,但我已经编写了答案以符合 OP 的要求 尝试相同,除了两个调用的开销。这就像有人要求将论点放在不同的行中一样有意义。【参考方案2】:

您需要将具体类注册为IStorageTableQueryHelper 实现,而不是抽象类。

services.AddScoped<IStorageTableQueryHelper, StorageTableQueryHelper>();

DI 容器只会解析您注册的类型。它不会尝试查找其中一个已注册类型是从另一个继承还是实现了接口。如果有 2 或 3 个实现该接口的类怎么办?

这就是为什么你不能只注册一个具体类型并注入它实现的接口。

抽象类根本没有注册,所以无法解析。下面的构造函数总是会失败:

public EShopBusinessLogicProcessor(StorageTableQueryAbstractHelper)

要完成这项工作,需要进行以下注册:

services.AddScoped<StorageTableQueryAbstractHelper, StorageTableQueryHelper>();

【讨论】:

2 个或更多实现接口的类可以使用键名在 DI 中注册,这不是问题。我想使用从抽象类派生的类作为可以有多个实现的DI @DineshTripathi 我知道。但这里不是这种情况。你没用过钥匙。你甚至还没有注册StorageTableQueryAbstractHelper。除非您使用密钥,否则您必须将接口与具体类一起注册,或者要求特定类型。

以上是关于.Net Core DI 注入抽象类在派生类中使用接口的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Core Web 应用程序系列- 使用ASP.NET Core内置的IoC容器DI进行批量依赖注入(MVC当中应用)

抽象类中的依赖注入,ASP.NET Core

ASP.NET Core使用编译时依赖关系注入(DI)

ASP.NET Core中的依赖注入:依赖注入(DI)

ASP.NET Core 依赖注入(DI)

ASP.NET Core Web 应用程序系列- 在ASP.NET Core中使用Autofac替换自带DI进行批量依赖注入(MVC当中应用)