Home > Mobile >  Dependency Injection with inheritance and Generics in .NET Core
Dependency Injection with inheritance and Generics in .NET Core

Time:05-31

I have the following minimal, reproducible example.

public class BaseEntity{}    
public class BaseChildClass: BaseEntity{}    
public class ChildA : BaseChildClass {}
public class ChildB : BaseChildClass {}

public interface IRepository<TEntity> where TEntity : BaseEntity{}

public class DataRepository<TEntity> : IRepository<TEntity>
    where TEntity : BaseEntity{}

public class Program
{
    public static void Main()
    {
        var services = new ServiceCollection();

        if (ChildAFeature) // loaded from config
        {
          services.AddScoped<IRepository<BaseChildClass>, DataRepository<ChildA>>();
        }
        else
        {
          services.AddScoped<IRepository<BaseChildClass>, DataRepository<ChildB>>();
        }

        var provider = services.BuildServiceProvider();
        
        var service = provider.GetService<BaseChildClass>();
        
        Console.WriteLine(service.GetType());
    }
}

The problem is when trying to inject service like this:

services.AddScoped<IRepository<BaseChildClass>, DataRepository<ChildA>>();

Compile error shows

there is no implicit convertion from DataRepository<ChildA> to IRepository<BaseChildClass>

I need to inject either ChildA or ChildB to the repository depending on a feature flag. So basically, some times I need childA repo and sometimes childB repo based on a condition.

CodePudding user response:

You are doing the service registrations in the wrong way.

Updated your dot-net fiddle Fiddle Link.

Here's the way to register generic dependencies.

public static void Main()
{
    var services = new ServiceCollection();
    services.AddScoped(typeof(IRepository<>), typeof(DataRepository<>));
    services.AddScoped<BaseChildClass, ChildA>();
    var provider = services.BuildServiceProvider();
    
    var repo = provider.GetService<IRepository<ChildA>>();

    Console.WriteLine(repo.GetType());
    
    var service = provider.GetService<BaseChildClass>();
    
    Console.WriteLine(service.GetType());
}

CodePudding user response:

Generic parameters don't really work with inheritance.

You can however declare the T in the interface as <out T>, then your use case should work. This does however force you to only use T as a return value, not as an input value. You can take a look at how IEnumerable<T> is declared, it does this too.

  • Related