简体   繁体   中英

Dependency injection for generic class

I have a generic class and a generic interface like this:

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;
}

Now in my StartUp.cs I'm hooking up the class and interface

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

When I try to use it in my eg Repository.cs its always null.

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

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

EDIT Here is the requested Repository Interface and class

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

And the Repository.cs class

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();
        ...
    }
    ...
}
services.AddTransient(typeof(IDataService<>), typeof(DataService<>));

Ideally this should not be allowed, but as method accepts type as parameter, it took it without performing any validation. As nobody expected anyone would try to use it.

The reason it is null, because typeof(IDataService<>) !== typeof(IDataService<SomeClass>)

You can check example at https://dotnetfiddle.net/8g9Bx7

That is the reason, DI resolver will never know how to resolve. Most DI containers resolve types only if type implements requested interface or has base class as requested class.

Any DI container will resolve type A for type B, only if A inherits B or A implements B.

In your case, DataService<> implements IDataService<> , but DataService<T> does not implement IDataService<>

Only way you can make it work is by calling same for every data type

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

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

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

OR

You can create a 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>();
     }
}

And register

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

Microsoft's Logging extension uses open generics in their service collection configuration

 services.TryAdd(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(Logger<>)));

That line lets the closed version of the logger class be injected as

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

Testing shows that, for a shared service scope, each different type of T will map to a different instance of the service, and that any valid type T that can be requested

If you want to play around with this, use this testbed: https://dotnetfiddle.net/dVDqnj

This approach assumes that behavior is not defined for specific implementations of the interface, but is more informational. If you need different implementations for IGeneric<Foo> and IGeneric<Bar> , you'll need to define each implementing service individually.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM