为什么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
其他答案是正确的,但有理由说明为什么编译器将此标记为不安全。 假设我们允许它; 怎么可能出错?
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
必须是不变的。