关于泛型函数参数的问题

时间:2010-08-06 05:08:24

标签: c#

我只是想知道为什么将System.Collections.Generic.List<string>传递给此函数test(ICollection<object> t)不起作用,为什么我不能将string传递给test2(object t)

对我来说没有多大意义!

4 个答案:

答案 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的泛型参数限制为方便的基类。