Pomoc dotycząca błędu C # generics - „Typ„ T ”musi być typem wartości niepodlegającym wartości null”

100

Jestem nowy w C # i nie rozumiem, dlaczego poniższy kod nie działa.

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

Podczas kompilacji daje następujący błąd:

Typ „T” musi być typem wartości niepodlegającym wartości null, aby można go było użyć jako parametru „T” w typie lub metodzie ogólnej „System.Nullable <T>”
Josh Kelley
źródło
1
Błąd kompilatora podaje wiersz definicji funkcji, ponieważ tam jest błąd.
SLaks

Odpowiedzi:

181

Musisz dodać T : structograniczenie:

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

W przeciwnym razie C # spróbuje dowiedzieć się, co to Nullable<T>znaczy i zda sobie sprawę, że nie ma już ograniczenia wymaganego przez Nullable<T>siebie. Innymi słowy, możesz spróbować zadzwonić:

CoalesceMax<string>(...)

co nie miałoby sensu, ponieważ Nullable<string>nie jest ważne.

Jon Skeet
źródło
A co z flagą C # 8 Not nullable?
kirin z domu
1
@kirinnee: nie, ponieważ Nullable<T>nadal musi Tbyć typem wartości niedopuszczającym wartości null, a nie tylko typem niedopuszczającym wartości null.
Jon Skeet
16

Nullable<T>Typu ma ograniczenia na to, że wymaga T, aby być typem wartość ( structw C #). Dlatego kompilator mówi ci o funkcji, Nullable<T>a nie stronie wywołania tej funkcji - to Nullableklasa jest główną przyczyną błędu, więc jest to bardziej pomocne, jeśli kompilator po prostu wskazał twoją funkcję i powiedział „to nie w porządku, napraw to!” (Wyobraź sobie, że CoalesceMaxużyłeś kilku rodzajów i naruszyłeś ograniczenie tylko jednego z nich - bardziej przydatna jest wiedza, który rodzaj generyczny ma złamane ograniczenie, niż po prostu wiedzieć, że jedno lub więcej ograniczeń w programie CoalesceMaxzostało zerwanych).

Rozwiązaniem jest uczynienie Ciebie Ti ich Tkompatybilnych poprzez wprowadzenie tego samego ograniczenia. Odbywa się to poprzez dodanie structograniczenia, które musi występować przed wszystkimi interfejsami / nowymi ograniczeniami:

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

źródło
6

Twoja ogólna metoda używa pliku Nullable<T>.

Jednak nie ograniczasz rodzaju T, więc może to skończyć się byciem Nullable<Form>, co jest oczywiście nieprawidłowe.

Musisz zmienić ograniczenie, aby where T : struct, IComparableupewnić się, że Tmoże to być tylko typ wartości.

SLaks
źródło
2

Nie do końca odpowiedź na OP, ale ponieważ była to pierwsza rzecz, która wyskoczyła w Google z tym samym komunikatem o błędzie, musiałem dodać ograniczenie do mojej definicji klasy, a nie mojej metody, np.

public class MyClass<T> where T : struct
{
    public void MyMethod(T? value)
    {
    }
}
3-14159265358979323846264
źródło