简体   繁体   English

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

[英]C# Type Conversion Error Despite Generic Constraint

Why, with a generic constraint on type parameter T of class P of "must inherit from A", does the first call succeed but the second call fail with the type conversion error detailed in the comment: 为什么在类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>' */
    }
}

Shouldn't the generic constraint ensure that List<T> is indeed ICollection<A> ? 如果不是通用约束确保List<T> 确实 ICollection<A>

This is an example of C#'s lack of covariance on generic types (C# does support array covariance). 这是C#的缺乏的一例协方差泛型类型(C# 的确支持阵列协方差)。 C# 4 will add this feature on interface types and also will update several BCL interface types to support it as well. C#4将在接口类型上添加此功能,还将更新一些BCL接口类型以支持该功能。

Please see C# 4.0: Covariance and Contravariance : 请参见C#4.0:协方差和协方差

In this article I'll try to cover one of the C# 4.0 innovations. 在本文中,我将尝试介绍C#4.0的一项创新。 One of the new features is covariance and contravariance on type parameters that is now supported by generic delegates and generic interfaces. 新功能之一是类型参数的协方差和协变,现在通用委托和通用接口都支持它们。 First let's see what does these words mean :) 首先让我们看看这些词是什么意思:)

The constraint has no effect on the problem; 约束对问题没有影响; the issue is that you're passing a List in a parameter that requires ICollection--C# doesn't support covariance so you need to explicitly cast the list to an ICollection: 问题是您在需要ICollection的参数中传递列表-C#不支持协方差,因此您需要将列表显式转换为ICollection:

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

You have strongly typed the parameter for DoSecond as type ICollection<A>. 您已将DoSecond的参数强烈键入为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>. 尽管T为A类型,但在编译时List <T>和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. 在调用DoSecond时,您将需要创建列表并将其转换为ICollection <A>,或者使DoSecond本身成为通用方法。

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. 注意:这种类型的隐式强制转换应在C#4.0中得到支持,与C#3.0提供的功能相比,它将提供大大改善的协方差。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM