Covariance和Contravariance相关的问题是什么?

时间:2012-09-13 23:17:28

标签: c# generics covariance contravariance

我有以下代码:

class Header<TItem> where TItem : IItem { IEnumerable<TItem> Item { get; set; } }
class HeaderA : Header<ItemA> { public HeaderA(int a) {...} } 
class HeaderB : Header<ItemB> { public HeaderB(int b) {...} } 

interface IItem {...}
class ItemA : IItem { }
class ItemB : IItem { }

public static List<Header<IItem>> list = new List<Header<IItem>> 
{
    new HeaderA(1)
}

上一个new HeaderA(1)的编译错误是

Error   1   The best overloaded Add method
'System.Collections.Generic.List<NS.Header<NS.IItem>>.Add(NS.Header<NS.IItem>)'
for the collection initializer has some invalid arguments

如何解决问题?

1 个答案:

答案 0 :(得分:7)

您正在尝试向Header<ItemA>添加List<Header<IItem>>。这需要从Header<ItemA>转换为Header<IItem> - 并且转换不存在。它不存在是有充分理由的。想象一下你的代码是有效的...那么这将有效:

List<Header<IItem>> list = ...; // As per code
Header<IItem> header = list[0];
header.Item = new List<IItem>();

现在请记住,header 实际上是 a HeaderA - 所以这项工作相当于此     HeaderA header = new HeaderA();     header.Item = new List {new ItemB()};

当其他任何事情都希望header.Item成为IEnumerable<ItemA>();时,那就不好了 - 所以这个应该没问题:

ItemA itemA = header.Item.First();

...如果你在那里添加ItemB,显然不会。

基本上,您正在寻找通用协方差 - 但您只能在接口和委托上声明(而不是在诸如Header<TItem>之类的类上),并且仅在类型参数不是由于Item setter而在输入位置使用。

也许更重要的是,你的设计看起来非常复杂 - 我强烈怀疑如果你退后一步,你可以设计你的方法,试图做到这一点。