Справка по ошибке универсальных шаблонов C # - «Тип 'T' должен быть типом значения, не допускающим значения NULL»


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

При компиляции выдает следующую ошибку:

Тип 'T' должен быть типом значения, не допускающим значения NULL, чтобы использовать его в качестве параметра 'T' в универсальном типе или методе 'System.Nullable <T>'

1
Ошибка компилятора дает вам строку с определением функции, потому что это ошибка.
SLaks

Ответы:


181

Вам нужно добавить 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>недействительно.


А как насчет флага C # 8 Not NULL?
Кирин в девичестве

1
@kirinnee: Нет, потому что по- Nullable<T>прежнему должен Tбыть тип значения, не допускающий значение NULL, а не просто тип, не допускающий значения NULL.
Джон Скит,

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)
    {
    }
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.