IList <ilist <int >>不接受List <list <int >>?

时间:2019-05-17 05:30:03

标签: c# generics

List实现IList,所以我希望IList可以接受List对象 但是为什么IList>不接受List>?

static IList<int> List_1()
    {
        List<int> list = new List<int> { 1,2,3,3,4,5};

        return list;
    }

    static IList<IList<int>> List_2()
    {
        List<List<int>> parent = new List<List<int>>();
        List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
        parent.Add(list);

        return parent; //compiler error CS0266
    }

5 个答案:

答案 0 :(得分:1)

假设这可行。您的客户代码为:

var result = List_2();

由于合同允许将IList<int>的任何内容添加到结果中,因此您可能拥有

public class MyCustomIList : IList<int>
{
    ...
}

然后

var result = List_2();
result.Add( new MyCustomIList() );

但这是错误的!

您的resultList<int>的列表,不允许您在其中添加List<int>或其派生词以外的任何内容。但是,您可以将{strong>不相关的MyCustomIList添加到List<int>

如果您需要全面了解此问题,请阅读covariance and contravariance上的更多信息。

此特定示例中的基本问题来自Add操作。如果您不需要它,IEnumerable就可以

static IEnumerable<IEnumerable<int>> List_2()
{
    List<List<int>> parent = new List<List<int>>();
    List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
    parent.Add(list);

    return parent; // no error, this works
}

这是covered already

答案 1 :(得分:1)

那是因为

List<T>实现了IList<T>,但

List<List<T>>未实现IList<IList<int>>

这就是为什么您的第一种方法能够按预期工作而第二种方法却无法工作的原因。

只需将第二种方法中的列表声明更改为

List<IList<int>> parent = new List<IList<int>>();

协方差和逆方差就是这种情况。

泛型类型参数支持协方差和协方差,但您需要以这种方式进行定义

通过docs.microsoft.com

  

协方差和逆方差是指使用比最初指定的类型更多的派生类型(更特定)或更少的派生类型(较不特定)的能力的术语。通用类型参数支持协方差和协方差,从而在分配和使用通用类型时提供了更大的灵活性

答案 2 :(得分:0)

  

为什么List会实现IList?

     

有点奇怪,因为除对象以外的任何类型的List都没有   履行IList的全部合同。这可能是为了使其更容易   正在更新旧的C#1.0代码以使用泛型的人员;那些人   可能已经确保只有正确的类型进入   他们的名单。在大多数情况下,当您传递IList时,   因此被叫方可以通过索引访问列表,而不是这样   它可以添加任意类型的新项目。

我建议返回IEnumerable而不是IList,这将简化您的工作,因为List完全实现了它。

答案 3 :(得分:0)

我不知道您为什么要完全返回IList<IList<int>>,但是一种实现方法是使用Cast<T>() method

static IList<IList<int>> List_2()
{
    List<List<int>> parent = new List<List<int>>();
    List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
    parent.Add(list);

    return parent.Cast<IList<int>>().ToList();
}

ConvertAll() method

return parent.ConvertAll(x => (IList<int>)x);

这两种方法都将遍历所有元素,并将它们强制转换/转换为给定类型,所以我认为最好返回IList<List<int>>(如果可能)。

答案 4 :(得分:0)

问题出在您的方法return type上。修改方法签名以返回到IList<List<int>>,而不是返回IList<IList<int>>

static IList<List<int>> List_2()
    {
        List<List<int>> parent = new List<List<int>>();
        List<int> list = new List<int> { 1, 2, 3, 3, 4, 5 };
        parent.Add(list);

        return parent; //no compiler error
    }

现在,它将正常工作,因为您的方法现在返回IList中的List<int>