为什么List 在协变接口MyInterface 上无效

跟进前一个问题的问题 ,这被认为是一个共同变异问题。 更进一步,如果我按如下方式修改IFactory

 class Program { static void Main(string[] args) { IFactory factory = new Factory(); } } class Factory : IFactory { } class Product : IProduct { } interface IFactory where T : IProduct { List MakeStuff(); } interface IProduct { } 

我明白了:

方差无效:类型参数T必须在Sandbox.IFactory.MakeStuff()上不变地有效。 T是协变的。

为什么这不是无效的? 该如何/应该如何解决?

@Craig的回答是正确的。 要解决,请将其更改为:

 IEnumerable MakeStuff() 

编辑:至于原因,请看IEnumerable 接口的定义:

 public interface IEnumerable : IEnumerable 

请注意, IList 接口没有out关键字。 接口和委托中的generics类型参数支持方差,而不支持类,因此它不适用于List

其他答案是正确的,但有理由说明为什么编译器将此标记为不安全。 假设我们允许它; 怎么可能出错?

 class Sprocket: Product {} class Gadget : Product {} class GadgetFactory : IFactory { public List MakeStuff() { return new List() { new Gadget(); } } } ... later ... IFactory gf = new GadgetFactory(); IFactory pf = gf; // Covariant! List pl = pf.MakeStuff(); // Actually a list of gadgets pl.Add(new Sprocket()); 

嘿,我们刚刚将一个链轮添加到一个只能包含小工具的列表中。

只有一个地方编译器可以检测到问题,这就在接口的声明中。

对于有点过于乐观的错误消息感到抱歉。 我无法想出更好的东西。

因为您可以在List添加和删​​除对象,所以即使列表是函数结果, T必须始终是不变的。 执行var l = MakeStuff()您可以将内容放入列表中或将其取出,因此T必须是不变的。