依赖项注入通用抽象的 IEnumerable class

Dependency injecting an IEnumerable of generic abstract class

我有多个 class 扩展通用抽象基础 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> {}

一切正常,我正在努力解决的是用于注册通用抽象基础 class 的许多实现的依赖注入,所以我想要的是:

IEnumerable<Base<BaseDetails>> _baseClasses;

我试过这样 DI 但没有成功:

builder.RegisterMany(new[] { Assembly.Load(nameof(Program)) }, type => type.IsAssignableTo(typeof(Base<>)));

我觉得我在 DI 方面遗漏了一些东西,非常感谢任何帮助!

像这样:

builder.RegisterMany(new[] { Assembly.Load(nameof(Program)) },
 type => type.IsGeneric && type.GetGenericTypeDefinition() == typeof(Base<>)));

欢迎来到 covariance and contravariance 的世界。虽然 IEnumerable<T> 是协变的,但您的 Base<T> class 不是,因为 classes 不能对它们应用任何方差。只有接口和委托可以。这意味着以下代码无法编译:

Base<BaseDetails> b = new A();

上面这段代码是一个重要的练习,因为当涉及到泛型时,DI 容器很容易让你误以为问题出在 DI 容器中。始终尝试在不使用 DI 容器的情况下通过 hand-wiring 您的对象图来重建问题。例如:

IEnumerable<Base<BaseDetails>> _baseClasses = new Base<BaseDetails>[]
{
    new A(), // <- compile error here
    new B(), // <- compile error here
};

同样,此代码无法在 C# 中编译:

CS0029 Cannot implicitly convert type 'A' to 'Base'

要实现此功能,您必须将 Base<T> 更改为接口并使其 T 泛型参数协变:

public interface Base<out T> { }