Parameter with type of IEnumerable<IEnumerable<string>> accepts List<List<string>> while IEnumerable<(int, IEnumerable<string>)> doesn't?

c# .net generics

62 观看

1回复

9154 作者的声誉

I have a class

public class Test
{
    public void M1(IEnumerable<IEnumerable<string>> p) { }
    public void M2(IEnumerable<(int, IEnumerable<string>)> p) { }
}
var t = new Test();

And the following code works fine.

var d1 = new List<List<string>> { new List<string>{ "test" } };
t.M1(d1);

However, the following code gets the error

var d2 = new List<(int, List<string>)> { (1, new List<string>{ "test" }) };
t.M2(d2);

cannot convert from 'System.Collections.Generic.List<(int, System.Collections.Generic.List)>' to 'System.Collections.Generic.IEnumerable<(int, System.Collections.Generic.IEnumerable)>'

d2 has to be defined as

var d2 = new List<(int, IEnumerable<string>)> { (1, new List<string>{ "test" }) };

Parameter with type of IEnumerable<IEnumerable<string>> accepts List<List<string>> while IEnumerable<(int, IEnumerable<string>)> doesn't accept List<(int, List<string>)>?

作者: ca9163d9 的来源 发布者: 2017 年 12 月 27 日

回应 1


4

2808 作者的声誉

决定

It has to do with covariance and contravariance.

IEnumerable<out T> is covariant so you can assign a more derived type of T and all will be fine => IEnumerable<Base> b = new List<DerivedFromBase>();

But in your case IEnumerable<(int, IEnumerable<string>)> is the same as IEnumerable<ValueTuple<int, IEnumerable<string>>> and because ValueTuple<int, List<string>> is not a derived type from ValueTuple<int, IEnumerable<string>>you cannot use it that way.

Update thanks to @JeppeStigNielsen

The main reason is because covariant never works with value types and the new tuples of C# 7 are value types, and also ValueType<T1, T2> is not covariant in T2

作者: fmaccaroni 发布者: 2017 年 12 月 27 日
32x32