我上课了
public class Test
{
public void M1(IEnumerable<IEnumerable<string>> p) { }
public void M2(IEnumerable<(int, IEnumerable<string>)> p) { }
}
var t = new Test();
以下代码工作正常。
var d1 = new List<List<string>> { new List<string>{ "test" } };
t.M1(d1);
但是,以下代码会收到错误
var d2 = new List<(int, List<string>)> { (1, new List<string>{ "test" }) };
t.M2(d2);
无法从'System.Collections.Generic.List <(int,System.Collections.Generic.List)>'转换为'System.Collections.Generic.IEnumerable <(int,System.Collections.Generic.IEnumerable)>'
d2
必须被定义为
var d2 = new List<(int, IEnumerable<string>)> { (1, new List<string>{ "test" }) };
类型为IEnumerable<IEnumerable<string>>
的参数接受List<List<string>>
而IEnumerable<(int, IEnumerable<string>)>
不接受List<(int, List<string>)>
?
它与covariance and contravariance有关。
IEnumerable<out T>
是协变的,所以你可以指定一个更加派生的T类型,一切都会很好=> IEnumerable<Base> b = new List<DerivedFromBase>();
但在你的情况下IEnumerable<(int, IEnumerable<string>)>
与IEnumerable<ValueTuple<int, IEnumerable<string>>>
相同,因为ValueTuple<int, List<string>>
不是来自ValueTuple<int, IEnumerable<string>>
you的衍生类型,所以不能那样使用它。
感谢@JeppeStigNielsen的更新
主要原因是因为协变从不与值类型一起使用,而C#7的新元组是值类型,并且ValueType<T1, T2>
在T2中也不是协变的