C#类型转换错误,尽管通用约束

时间:2009-07-31 19:51:40

标签: c# generics type-conversion covariance constraints

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

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>吗?

3 个答案:

答案 0 :(得分:7)

这是C#在泛型类型上缺少covariance的示例(C# 支持数组协方差)。 C#4将在接口类型上添加此功能,并且还将更新多个BCL接口类型以支持它。

请参阅C# 4.0: Covariance and Contravariance

  

在本文中,我将尝试涵盖一个   C#4.0创新。其中一个   新功能是协方差和   类型参数的逆变   现在由通用代表支持   和通用接口。首先让我们   看看这些词是什么意思:)

答案 1 :(得分:0)

约束对问题没有影响;问题是你在一个需要ICollection的参数中传递List - C#不支持协方差,所以你需要显式地将列表转换为ICollection:

S.DoSecond((ICollection<A>) new List<T>());      // this call will be happy

答案 2 :(得分:0)

您已强烈键入DoSecond的参数作为类型ICollection&lt; A&gt;。尽管T是A类型的事实,但在编译时,List&lt; T&gt;之间没有隐式强制转换。和ICollection&lt; A&gt;。您将需要创建列表并将其强制转换为ICollection&lt; A&gt;当你调用DoSecond时,或者让DoSecond本身成为通用方法。

注意:C#4.0应该支持这种类型的隐式强制转换,这将提供比C#3.0提供的更好的协变性。