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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2230657/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-07 00:35:16  来源:igfitidea点击:

Help with C# generics error - "The type 'T' must be a non-nullable value type"

c#generics

提问by Josh Kelley

I'm new to C# and don't understand why the following code doesn't work.

我是 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;
}

It gives the following error during compilation:

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

The type 'T' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable<T>'
类型“T”必须是不可为空的值类型,以便将其用作泛型类型或方法“System.Nullable<T>”中的参数“T”

采纳答案by Jon Skeet

You need to add a T : structconstraint:

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

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

Otherwise C# will try to work out what Nullable<T>means, and realise that it doesn't already have the constraint required by Nullable<T>itself. In other words, you could try to call:

否则 C# 将尝试找出什么Nullable<T>意思,并意识到它本身还没有所需的约束Nullable<T>。换句话说,您可以尝试调用:

CoalesceMax<string>(...)

which wouldn't make sense, as Nullable<string>isn't valid.

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

回答by SLaks

Your generic method is using a Nullable<T>.

您的通用方法正在使用Nullable<T>.

However, you aren't constraining the type of T, so it could end up being Nullable<Form>, which is obviously invalid.

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

You need to change the constraint to where T : struct, IComparableto ensure that Tcan only be a value type.

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

回答by SLaks

The Nullable<T>type has a constraint on it that requires Tto be a value type (structin C#). That's why the compiler is telling you about Nullable<T>and not your function or the call site of that function -- it's the Nullableclass that is the root cause of the error, so this is actually more helpful that if the compiler just pointed to your function and said "this ain't right, fix it!" (Imagine if CoalesceMaxused several generics, and violated the constraint on only one of them - it's more useful to know which generic had its constraint broken than to just know that one or more constraints in CoalesceMaxwere broken).

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

The solution is to make your Tand their Tcompatible by introducing the same constraint. This is done by adding the structconstraint, which must come before all interface / new constraints:

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

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

回答by 3-14159265358979323846264

Not exactly an answer to the OP but since this was the first thing that popped up on google for the same error message, I had to add the constraint on my class definition, rather than my method, eg

不完全是 OP 的答案,但由于这是在 google 上弹出相同错误消息的第一件事,我不得不在我的类定义上添加约束,而不是我的方法,例如

public class MyClass<T> where T : struct
{
    public void MyMethod(T? value)
    {
    }
}