Справка с ошибкой С# generics - "Тип" T "должен быть невообразимым типом значения"

Я новичок в С# и не понимаю, почему следующий код не работает.

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' должен быть невообразимым типом значения, чтобы использовать его как параметр 'T' в общем типе или методе 'System.Nullable <T> '

Ответ 1

Вам нужно добавить ограничение T : struct:

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

В противном случае С# попытается понять, что означает Nullable<T>, и поймет, что у него еще нет ограничения, требуемого самим Nullable<T>. Другими словами, вы можете попробовать позвонить:

CoalesceMax<string>(...)

что не имеет смысла, так как Nullable<string> недействителен.

Ответ 2

Тип Nullable<T> имеет ограничение на него, для которого T требуется тип значения (struct в С#). Вот почему компилятор говорит вам о Nullable<T>, а не о вашей функции или сайте вызова этой функции - это класс Nullable, который является основной причиной ошибки, поэтому на самом деле это более полезно, если только компилятор просто указал на вашу функцию и сказал: "Это неправильно, исправьте!" (Предположим, что если CoalesceMax использовал несколько дженериков и нарушил ограничение только на одном из них - было бы более полезно узнать, какой из родословных нарушил его ограничение, а просто знать, что одно или несколько ограничений в CoalesceMax были сломаны).

Решение состоит в том, чтобы сделать ваши T и их T совместимыми, введя такое же ограничение. Это делается путем добавления ограничения struct, которое должно появиться перед всеми интерфейсами/новыми ограничениями:

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

Ответ 3

В вашем общем методе используется Nullable<T>.

Однако вы не ограничиваете тип T, поэтому он может оказаться Nullable<Form>, что явно недействительно.

Вам нужно изменить ограничение на where T : struct, IComparable, чтобы гарантировать, что T может быть только типом значения.

Ответ 4

Не совсем ответ на OP, но поскольку это первое, что появилось в google для того же сообщения об ошибке, мне пришлось добавить ограничение на определение моего класса, а не мой метод, например

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