3

为什么,对“必须继承自 A”的类 P 的类型参数 T 的通用约束,第一次调用成功但第二次调用失败,注释中详述了类型转换错误:

abstract class A { }

static class S
{
    public static void DoFirst(A argument) { }
    public static void DoSecond(ICollection<A> argument) { }
}

static class P<T>
    where T : A, new()
{
    static void Do()
    {
        S.DoFirst(new T());             // this call is OK

        S.DoSecond(new List<T>());      // this call won't compile with:

        /* cannot convert from 'System.Collections.Generic.List<T>'
           to 'System.Collections.Generic.ICollection<A>' */
    }
}

通用约束不应该确保List<T> 确实如此ICollection<A>吗?

4

3 回答 3

7

这是 C#在泛型类型上缺乏协变的一个例子(C#确实支持数组协变)。C# 4 将在接口类型上添加此功能,并且还将更新几个 BCL 接口类型以支持它。

请参阅C# 4.0:协变和逆变

在本文中,我将尝试介绍 C# 4.0 的一项创新。新特性之一是类型参数的协变和逆变,现在由泛型委托和泛型接口支持。首先让我们看看这些词是什么意思:)

于 2009-07-31T19:54:46.303 回答
0

约束对问题没有影响;问题是您在需要 ICollection 的参数中传递了一个列表——C# 不支持协方差,因此您需要将列表显式转换为 ICollection:

S.DoSecond((ICollection<A>) new List<T>());      // this call will be happy
于 2009-07-31T19:57:34.487 回答
0

You have strongly typed the parameter for DoSecond as type ICollection<A>. Despite the fact that T is of type A, at compile time there is no implicit cast between List<T> and ICollection<A>. You will either need to create the list and cast it to ICollection<A> when you call DoSecond, or make DoSecond a generic method itself.

NOTE: This type of implicit cast should be supported in C# 4.0, which will provide much improved co/contravariance over what C# 3.0 offers.

于 2009-07-31T19:57:52.803 回答