Aide sur l'erreur générique C # - "Le type 'T' doit être un type valeur non Nullable"

100

Je suis nouveau en C # et je ne comprends pas pourquoi le code suivant ne fonctionne pas.

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

Il donne l'erreur suivante lors de la compilation:

Le type 'T' doit être un type valeur non Nullable pour pouvoir l'utiliser comme paramètre 'T' dans le type ou la méthode générique 'System.Nullable <T>'
Josh Kelley
la source
1
L'erreur du compilateur vous donne la ligne de la définition de la fonction car c'est là que se trouve l'erreur.
SLaks

Réponses:

181

Vous devez ajouter une T : structcontrainte:

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

Sinon, C # essaiera de comprendre ce que Nullable<T>signifie et réalisera qu'il n'a pas déjà la contrainte requise par Nullable<T>lui-même. En d'autres termes, vous pouvez essayer d'appeler:

CoalesceMax<string>(...)

ce qui n'aurait pas de sens, car ce Nullable<string>n'est pas valide.

Jon Skeet
la source
16

Le Nullable<T>type a une contrainte qui nécessite Td'être un type valeur ( structen C #). C'est pourquoi le compilateur vous parle Nullable<T>et non de votre fonction ou du site d'appel de cette fonction - c'est la Nullableclasse qui est la cause première de l'erreur, donc c'est en fait plus utile que si le compilateur a juste pointé votre fonction et dit "Ce n'est pas bien, réparez-le!" (Imaginez si vous CoalesceMaxutilisez plusieurs génériques et enfreignez la contrainte sur un seul d'entre eux - il est plus utile de savoir quel générique a eu sa contrainte cassée que de simplement savoir qu'une ou plusieurs contraintes dans CoalesceMaxont été rompues).

La solution est de rendre votre Tet leur Tcompatible en introduisant la même contrainte. Cela se fait en ajoutant la structcontrainte, qui doit précéder toutes les interfaces / nouvelles contraintes:

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

la source
6

Votre méthode générique utilise un Nullable<T>.

Cependant, vous ne contraignez pas le type de T, donc cela pourrait finir par être Nullable<Form>, ce qui est évidemment invalide.

Vous devez modifier la contrainte sur where T : struct, IComparablepour vous assurer qu'il Tne peut s'agir que d'un type valeur.

SLaks
la source
2

Pas exactement une réponse à l'OP mais comme c'était la première chose qui est apparue sur google pour le même message d'erreur, j'ai dû ajouter la contrainte sur ma définition de classe, plutôt que sur ma méthode, par exemple

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