泛型类的依赖注入

时间:2017-09-03 09:24:35

标签: c# asp.net dependency-injection asp.net-core

我有一个泛型类和这样的通用接口:

public interface IDataService<T> where T: class
{
    IEnumerable<T> GetAll();
}

public class DataService<T> : IDataService<T> where T : class
{
    public IEnumerable<T> GetAll()
    {
        return Seed<T>.Initialize();
    }
}

public static IEnumerable<T> Initialize()
{
    List<T> allCalls = new List<T>();
    ....
    return allCalls;
}

现在在我的StartUp.cs中,我正在连接类和接口

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient(typeof(IDataService<>), typeof(DataService<>));
    ...
}

当我尝试在我的例如Repository.cs总是为null。

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDataService<T> _dataService;

    public Repository(IDataService<T> dataService)
    {
        _dataService = dataService;
    ...
    }
    ...
}

EDIT 这是请求的存储库接口和类

public interface IRepository<T> where T : class
{
    double GetCallPrice(T callEntity, Enum billingType);
    double GetCallPriceFromIdAndBillingType(int id, Enum billingType);
}

和Repository.cs类

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDataService<T> _dataService;
    private IEnumerable<T> _allCalls;

    public Repository(IDataService<T> dataService)
    {
        _dataService = dataService;
    }

    public double GetCallPrice(int id)
    {
        _allCalls = _dataService.GetAllCalls();
        ...
    }
    ...
}

2 个答案:

答案 0 :(得分:8)

services.AddTransient(typeof(IDataService<>), typeof(DataService<>));

理想情况下,这不应该被允许,但是当方法接受type作为参数时,它会在不执行任何验证的情况下接受它。没有人希望有人会尝试使用它。

它为空的原因,因为typeof(IDataService<>) !== typeof(IDataService<SomeClass>)

您可以在https://dotnetfiddle.net/8g9Bx7

查看示例

这就是原因,DI解析器永远不会知道如何解决。大多数DI容器仅在类型实现请求的接口或具有基类作为请求类时解析类型。

只有当A继承B或A实现B时,任何DI容器都将解析类型A的类型A.

在您的情况下,DataService<>实施IDataService<>,但DataService<T>未实施IDataService<>

只有你可以使它工作的方法是为每种数据类型调用相同的

services.AddTransient(typeof(IDataService<Customer>), typeof(DataService<Customer>));

services.AddTransient(typeof(IDataService<Order>), typeof(DataService<Order>));

services.AddTransient(typeof(IDataService<Message>), typeof(DataService<Message>));

您可以创建ServiceFactory ...

interface IDataServiceFactory{
     DataService<T> Get<T>();
}

class DataServiceFactory : IDataServiceFactory{
     public DataService<T> Get<T>(){
          //.. your own logic of creating DataService

          return new DataService<T>();
     }
}

并注册

services.AddTransient(typeof(IDataServiceFactory), typeof(DataServiceFactory));

答案 1 :(得分:1)

Microsoft 的 Logging 扩展在其 service collection configuration

中使用开放泛型
 services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));

该行允许将记录器类的封闭版本注入为

public SomeService(ILogger<SomeService> logger)
{
    // ...

测试表明,对于共享服务范围,每种不同类型的 T 将映射到不同的服务实例,并且可以请求的任何有效类型 T

如果你想玩这个,使用这个测试平台:https://dotnetfiddle.net/dVDqnj

这种方法假设行为不是为接口的特定实现定义的,而是更多的信息。如果您需要为 IGeneric<Foo>IGeneric<Bar> 实现不同的实现,则需要单独定义每个实现服务。