Autofac:类型“...”不可分配给服务“...”。

mik*_*ike 2 c# generics autofac

考虑以下类和接口:

interface IFactory<T>{}
class Factory<T> : IFactory<T>{ }

interface IEntity{}
class Entity : IEntity{ }
Run Code Online (Sandbox Code Playgroud)

我希望 Autofac 能够解决这样的IFactory<IEntity>问题Factory<Entity>

b.RegisterType<Factory<Entity>>().As<IFactory<IEntity>>();
Run Code Online (Sandbox Code Playgroud)

但我得到以下异常(为了清楚起见缩写):

The type 'Factory`1[Entity]' is not assignable to service 'IFactory`1[[IEntity]]'
Run Code Online (Sandbox Code Playgroud)

这是为什么?如何解决这个问题?或者我正在尝试一些“错误”的事情?

我简单地研究了一下RegisterGeneric,但我认为它不适用于这里;另外,因为上面只是一个例子。在其他情况下,我可能想为IFactory<IEntity>.

Jon*_*eet 5

这不是 Autofac 问题 - 这是通用方差问题。您会在简单的 C# 程序中看到完全相同的内容:

public class Program 
{
    public static void Main() 
    {
        IFactory<IEntity> factory = new Factory<Entity>();
    }
}
Run Code Online (Sandbox Code Playgroud)

大多数通用接口都是不变的——类型参数必须完全匹配。有些是协变的,例如IEnumerable<T>,允许您编写:

IEnumerable<object> objects = new List<string>();
Run Code Online (Sandbox Code Playgroud)

有些是逆变的,例如IComparer<T>,允许您编写:

IComparer<string> = Comparer<object>.Default;
Run Code Online (Sandbox Code Playgroud)

协变接口只允许它们的类型参数从实现中“出来”(例如通过返回类型)。逆变接口只允许它们的类型参数“进入”实现(例如通过常规参数)。当您拥有本身接受值等的委托参数时,它会变得微妙,但我们现在会忽略它......

听起来你IFactory<T>应该是协变的 - 所以你只需更改声明,如下所示:

interface IFactory<out T>{}
Run Code Online (Sandbox Code Playgroud)

到那时,代码就可以编译了,我希望Autofac 也能处理它。但这确实要求您的界面永远不会用作T输入。(我们无法判断,因为您没有显示任何接口成员。)

有关通用方差的更多详细信息,请参阅MS 文档