帮助解决C#泛型错误-“类型'T'必须是不可为空的值类型”


100

我是C#的新手,不理解为什么以下代码不起作用。

public static Nullable<T> CoalesceMax<T>(Nullable<T> a, Nullable<T> b) where T : IComparable
{
    if (a.HasValue && b.HasValue)
        return a.Value.CompareTo(b.Value) < 0 ? b : a;
    else if (a.HasValue)
        return a;
    else
        return b;
}

// Sample usage:
public DateTime? CalculateDate(DataRow row)
{
    DateTime? result = null;
    if (!(row["EXPIRATION_DATE"] is DBNull))
        result = DateTime.Parse((string)row["EXPIRATION_DATE"]);
    if (!(row["SHIPPING_DATE"] is DBNull))
        result = CoalesceMax(
            result
            DateTime.Parse((string)row["SHIPPING_DATE"]).AddYears(1));
    // etc.
    return result;
}

在编译过程中会出现以下错误:

为了在通用类型或方法“ System.Nullable <T>”中将其用作参数“ T”,类型“ T”必须为不可为空的值类型

1
编译器错误为您提供了函数定义所在的行,因为这是错误所在。
Slaks 2010年

Answers:


180

您需要添加一个T : struct约束:

public static Nullable<T> CoalesceMax<T>
    (Nullable<T> a, Nullable<T> b) where T : struct, IComparable

否则,C#将尝试找出Nullable<T>含义,并意识到它本身还没有约束Nullable<T>。换句话说,您可以尝试致电:

CoalesceMax<string>(...)

这是没有意义的,因为这Nullable<string>是无效的。


16

Nullable<T>类型具有约束,该约束需要T为值类型(struct在C#中)。这就是为什么编译器告诉您的信息Nullable<T>而不是您的函数或该函数的调用站点的原因-正是Nullable类是导致错误的根本原因,因此,如果编译器只是指向您的函数并说出了错误,这实际上会更有帮助“这是不对的,解决它!” (想象一下,如果CoalesceMax使用了多个泛型,并且仅对其中一个违反了约束,那么知道哪个泛型的约束已被破坏比仅仅知道一个或多个约束CoalesceMax已被破坏更有用)。

解决方案是通过引入相同约束来使您T和他们T兼容。这是通过添加struct约束来完成的,约束必须在所有接口/新约束之前出现:

public static Nullable<T> CoalesceMax<T>(Nullable<T> a, Nullable<T> b) where T : struct, IComparable{
  ...
}

6

您的通用方法使用Nullable<T>

但是,您并没有限制的类型T,因此最终可能是Nullable<Form>,这显然是无效的。

您需要更改约束以where T : struct, IComparable确保T只能是值类型。


2

不完全是对OP的答案,但是由于这是在Google上弹出的第一条错误消息,因此我必须在类定义而不是方法上添加约束,例如

public class MyClass<T> where T : struct
{
    public void MyMethod(T? value)
    {
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.