web-dev-qa-db-fra.com

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

Je suis nouveau sur 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 de valeur non nullable afin de l'utiliser comme paramètre 'T' dans le type ou la méthode générique 'System.Nullable <T>'
95
Josh Kelley

Vous devez ajouter une contrainte T: struct:

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

Sinon, C # essaiera de déterminer ce que Nullable<T> signifie, et réalisez 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, comme Nullable<string> n'est pas valide.

169
Jon Skeet

Le Nullable<T> type a une contrainte qui requiert que T soit un type valeur (struct en C #). C'est pourquoi le compilateur vous parle de Nullable<T> et non votre fonction ou le site d'appel de cette fonction - c'est la classe Nullable qui est la cause principale de l'erreur, donc c'est en fait plus utile que si le compilateur pointait simplement vers votre fonction et disait "ce n'est pas bien, corrige ça!" (Imaginez si CoalesceMax utilisait plusieurs génériques et violait la contrainte sur un seul d'entre eux - il est plus utile de savoir quel générique avait sa contrainte cassée que de savoir qu'une ou plusieurs contraintes dans CoalesceMax étaient cassés).

La solution est de rendre votre T et leur T compatibles en introduisant la même contrainte. Cela se fait en ajoutant la contrainte struct, qui doit précéder toutes les contraintes d'interface/nouvelles:

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

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

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

Vous devez remplacer la contrainte par where T : struct, IComparable pour garantir que T ne peut être qu'un type de valeur.

6
SLaks

Pas exactement une réponse à l'OP mais comme c'était la première chose qui apparaissait 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)
    {
    }
}