我只是想知道为什么将System.Collections.Generic.List<string>
传递给此函数test(ICollection<object> t)
不起作用,为什么我不能将string
传递给test2(object t)
?
对我来说没有多大意义!
答案 0 :(得分:7)
因为ICollection
不是仅输出接口,所以它不是协变的。
考虑以下代码:
void test(ICollection<object> t)
{
t.Add(new TextBox());
}
List<string> lst;
test(lst);
当test
尝试将TextBox
填入List<string>
时会发生什么?
ICollection<object>
的合同是任何object
都可以放入,而出来的项目总是object
类型。但List<string>
只满足合同的一半。
答案 1 :(得分:1)
因为在C#3.0和.NET 3.5或之前的List<T>
实现了ICollection<T>
。这意味着List和ICollection的泛型类型必须相同。
在这种情况下,虽然字符串是从对象派生的,但List<sting>
无法分配给List<object>
。同样,List<string>
无法分配给ICollection<object>
。
在C#4.0和.NET 4.0中,我们有协方差和反方差的概念,允许您将List<string>
分配给IEnumerable<object>
。
这是一段在C#4.0中运行的代码
public static void Test(IEnumerable<object> input) {
// do something
}
static void Main(string[] args) {
var input = new List<string>();
Test(input);
}
答案 2 :(得分:0)
方法test()
期望参数值是实现接口ICollection<object>
的类型。确保课程List
可以。
答案 3 :(得分:0)
@ Ben的解释很棒,是的@Gallahad建议,.Net 4.0中有很多有用的协变和逆变接口。这些允许你做你想做的事情,并保证Ben的例子中的陷阱代码不能用它们写。
与此同时,您当然可以做类似
的事情private static void PrintAll<T>(IEnumerable<T> list)
{
foreach (var item in list)
{
Console.WriteLine(item.ToString());
}
}
static void Main()
{
List<int> numbers = Enumerable.Range(1, 10).ToList();
PrintAll(numbers);
}
这是实现协方差的好方法。此外,您可以使用where子句将PrintAll的泛型参数限制为方便的基类。