返回IList <ilist <t>&gt; </ilist <t>

时间:2011-11-15 20:00:14

标签: c# generics interface ilist

我有一个构建列表列表的方法。我想让返回类型使用通用IList&lt;&gt;减少与具体List&lt;&gt;的耦合的界面下游类型。但是,编译器正在努力进行类型转换。

public IList<IList<T>> Foo<T>()
    {
        return new List<List<T>>();
    } 

为什么在这种情况下会失败:

public IList<T> Foo<T>()
    {
        return new List<T>();
    } 

这种混乱中最优雅的方式是什么?

2 个答案:

答案 0 :(得分:13)

这样做:

return new List<IList<T>>();

由于List<T>实施IList<T>,您可以在结果中添加任何类型的IList<T>。例如:

Foo<int>().Add(new List<int>());

关于为什么,这是协方差/逆变的问题(我总是将两者混为一谈)。基本上,如果您,您返回IList<IList<T>>,那么有人应该能够在结果中添加任何类型的IList<T>

Foo<int>().Add(new []{1}); // arrays implement `IList`

显然,如果您返回了List<List<T>>,则上述代码行将无效:您将尝试将T[]添加到List<T>的集合中。因此,即使List<T>IList<T>List<List<T>>也不是IList<IList<T>>

注意:下一部分仅适用于.NET 4及更高版本,因为这是第一个支持接口协方差和逆变的版本。

另一方面,如果您知道使用您的结果的人不打算在列表中添加任何内容,但只是尝试迭代它,您可以将返回类型更改为{{1}然后返回IEnumerable<IList<T>>就好了。为什么?因为List<List<T>>接口是协变

IEnumerable<T>

那&#34; out&#34;告诉编译器该接口只有返回public interface IEnumerable<out T> 相关的值的方法(如T),并且它不会有任何相关的方法以GetEnumerator作为参数(如T)。

答案 1 :(得分:1)

这与C#协方差和逆变有关。您可以阅读更多here

要做T接口的接口,你的接口必须都标记为out T或T. IEnumerable标记为out T。