列表实现了iList,所以我希望iList会接受列表对象但是为什么iList>不接受列表>?
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
}
那是因为
List<T>
实现IList<T>
但是
List<List<T>>
不实现IList<IList<int>>
这就是为什么您的第一个方法按预期工作,第二个方法不做。
只需在第二种方法中将列表的声明更改为
List<IList<int>> parent = new List<IList<int>>();
这就是协方差和违反的情况。
通用类型参数支持协方差和违反,但是您需要以这种方式定义
by Learn.microsoft.com
协方差和违反术语是指使用比最初指定的更派生类型(更具体(或派生类型较低的类型(更具体(的能力。通用类型参数支持协方差和违规参数在分配和使用通用类型方面提供更大的灵活性
假设这有效。您的客户端代码是:
var result = List_2();
由于合同允许添加结果IList<int>
的任何内容,因此您可能具有
public class MyCustomIList : IList<int>
{
...
}
,然后
var result = List_2();
result.Add( new MyCustomIList() );
但这是错误的!
您的result
是List<int>
的列表,除了List<int>
或其导数外,您不应添加其他内容。但是,您能够添加MyCustomIList
,即与List<int>
无关的。
如果您需要对问题的广泛了解,请阅读有关协方差和违反的更多信息。
此特定示例中的基本问题来自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
}
这已经涵盖了。
为什么列表列表实现iList?
这有点奇怪,因为除对象以外的任何类型的列表都不 履行ILIST的完整合同。可能是为了使其更容易 正在更新旧C#1.0代码的人使用仿制药;那些人 可能已经确保只有正确的类型进入 他们的清单。大多数时候 因此,Callee可以使列表访问列表,而不是这样 它可以添加任意类型的新项目。
我建议返回iEnumerable而不是iList,可以简化您的生活,因为列表完全实现了它。
问题是您的方法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
}
现在它可以正常工作,因为您的方法现在返回List<int>
的IList
我不知道为什么要准确返回IList<IList<int>>
,但是一种方法是使用Cast<T>()
方法:
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()
方法:
return parent.ConvertAll(x => (IList<int>)x);
这两种方法都将在所有元素上运行,然后将它们转换为给定类型,因此我认为最好返回IList<List<int>>
(如果可能的话(。