I have multiple classes which extend a generic abstract base class:
public class BaseDetails {}
public class ADetails : BaseDetails {}
public class BDetails : BaseDetails {}
public abstract class Base<T> {}
public class A : Base<ADetails> {}
public class B : Base<BDetails> {}
This is all working, what I am struggling with is the dependency injection for registering many implementations of the generic abstract base class, so what I would like is:
IEnumerable<Base<BaseDetails>> _baseClasses;
I have tried to DI this like so but with no luck:
builder.RegisterMany(new[] { Assembly.Load(nameof(Program)) }, type => type.IsAssignableTo(typeof(Base<>)));
I feel like I am missing something on the DI side of things, any help is much appreciated!
Welcome to the world of covariance and contravariance. While IEnumerable<T>
is covariant, your Base<T>
class isn't, because classes can't have any variance applied to them. Only interfaces and delegates can. This means that the following code does not compile:
Base<BaseDetails> b = new A();
This code above is an important exercise to do, because when it comes to generics, DI Containers can easily cause you to be mislead in thinking that the problem is in the DI Container. Always try to reconstruct the problem by hand-wiring your object graphs without the use of the DI Container. For instance:
IEnumerable<Base<BaseDetails>> _baseClasses = new Base<BaseDetails>[]
{
new A(), // <- compile error here
new B(), // <- compile error here
};
Again, this code will not compile in C#:
CS0029 Cannot implicitly convert type 'A' to 'Base'
To make this work, you will have to change Base<T>
to an interface and make its T
generic argument covariant:
public interface Base<out T> { }