Hilfe bei generischen C # -Fehlern - "Der Typ 'T' muss ein nicht nullbarer Werttyp sein"

100

Ich bin neu in C # und verstehe nicht, warum der folgende Code nicht funktioniert.

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

Beim Kompilieren wird der folgende Fehler angezeigt:

Der Typ 'T' muss ein nicht nullbarer Werttyp sein, um ihn als Parameter 'T' im generischen Typ oder in der generischen Methode 'System.Nullable <T>' zu verwenden.
Josh Kelley
quelle
1
Der Compilerfehler gibt Ihnen die Zeile der Funktionsdefinition an, da dort der Fehler liegt.
SLaks

Antworten:

180

Sie müssen eine T : structEinschränkung hinzufügen :

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

Andernfalls versucht C # herauszufinden, was Nullable<T>bedeutet, und stellt fest, dass es nicht bereits die für sich Nullable<T>selbst erforderliche Einschränkung aufweist . Mit anderen Worten, Sie könnten versuchen anzurufen:

CoalesceMax<string>(...)

Das würde keinen Sinn ergeben, da Nullable<string>es nicht gültig ist.

Jon Skeet
quelle
16

Der Nullable<T>Typ hat eine Einschränkung T, die ein Wertetyp sein muss ( structin C #). Aus diesem Grund erzählt Ihnen der Compiler Nullable<T>und nicht Ihre Funktion oder die Aufrufstelle dieser Funktion - es ist die NullableKlasse, die die Hauptursache für den Fehler ist. Dies ist also hilfreicher, als wenn der Compiler nur auf Ihre Funktion zeigte und dies sagte "Das ist nicht richtig, repariere es!" (Stellen Sie sich CoalesceMaxvor, Sie verwenden mehrere Generika und verletzen nur die Einschränkung für eines von ihnen. Es ist nützlicher zu wissen, bei welchem ​​Generikum die Einschränkung gebrochen wurde, als nur zu wissen, dass eine oder mehrere Einschränkungen darin enthalten sindCoalesceMax verletzt wurden.)

Die Lösung besteht darin, Ihre Tund ihre TKompatibilität durch Einführung derselben Einschränkung zu verbessern. Dies erfolgt durch Hinzufügen der structEinschränkung, die vor allen Schnittstellen- / neuen Einschränkungen stehen muss:

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

quelle
6

Ihre generische Methode verwendet a Nullable<T>.

Sie beschränken jedoch nicht die Art von T, so dass es am Ende sein kann Nullable<Form>, was offensichtlich ungültig ist.

Sie müssen die Einschränkung ändern, where T : struct, IComparableum sicherzustellen, dass Tdies nur ein Werttyp sein kann.

SLaks
quelle
2

Nicht gerade eine Antwort auf das OP, aber da dies das erste war, das bei Google für dieselbe Fehlermeldung auftauchte, musste ich die Einschränkung für meine Klassendefinition hinzufügen und nicht für meine Methode, z

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