首页 > 解决方案 > Autofac:类型“...”不可分配给服务“...”。

问题描述

考虑以下类和接口:

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

interface IEntity{}
class Entity : IEntity{ }

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

b.RegisterType<Factory<Entity>>().As<IFactory<IEntity>>();

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

The type 'Factory`1[Entity]' is not assignable to service 'IFactory`1[[IEntity]]'

为什么会这样?如何解决这个问题?还是我在尝试“错误”的东西?

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

标签: c#genericsautofac

解决方案


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

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

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

IEnumerable<object> objects = new List<string>();

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

IComparer<string> = Comparer<object>.Default;

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

听起来你IFactory<T>应该是协变的 - 所以你只需像这样更改声明:

interface IFactory<out T>{}

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

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


推荐阅读