Ayuda con el error genérico de C #: "El tipo 'T' debe ser un tipo de valor no anulable"

100

Soy nuevo en C # y no entiendo por qué el siguiente código no funciona.

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

Da el siguiente error durante la compilación:

El tipo 'T' debe ser un tipo de valor no anulable para poder usarlo como parámetro 'T' en el tipo o método genérico 'System.Nullable <T>'
Josh Kelley
fuente
1
El error del compilador le da la línea de la definición de la función porque ahí es donde está el error.
SLaks

Respuestas:

180

Necesita agregar una T : structrestricción:

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

De lo contrario, C # intentará averiguar qué Nullable<T>significa y se dará cuenta de que aún no tiene la restricción requerida por Nullable<T>sí mismo. En otras palabras, podría intentar llamar a:

CoalesceMax<string>(...)

que no tendría sentido, ya Nullable<string>que no es válido.

Jon Skeet
fuente
16

El Nullable<T>tipo tiene una restricción que requiere Tser un tipo de valor ( structen C #). Es por eso que el compilador le está informando sobre Nullable<T>su función o el sitio de llamada de esa función, y no sobre su función; es la Nullableclase la que es la causa raíz del error, por lo que esto es realmente más útil que si el compilador simplemente señaló su función y dijo "¡Esto no está bien, arréglalo!" (Imagínese si CoalesceMaxusa varios genéricos y violó la restricción en solo uno de ellos; es más útil saber qué genérico tuvo su restricción rota que saber simplemente que una o más restricciones CoalesceMaxse rompieron).

La solución es hacer que usted Ty ellos sean Tcompatibles introduciendo la misma restricción. Esto se hace agregando la structrestricción, que debe venir antes de todas las interfaces / nuevas restricciones:

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

fuente
6

Su método genérico está usando un Nullable<T>.

Sin embargo, no está restringiendo el tipo de T, por lo que podría terminar siendo Nullable<Form>, lo que obviamente no es válido.

Debe cambiar la restricción para where T : struct, IComparableasegurarse de que Tsolo pueda ser un tipo de valor.

SLaks
fuente
2

No es exactamente una respuesta al OP, pero como esto fue lo primero que apareció en Google para el mismo mensaje de error, tuve que agregar la restricción en la definición de mi clase, en lugar de mi método, por ejemplo

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