119 votes

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

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 pendant la compilation :

Le type 'T' doit être un type de valeur non nul afin de l'utiliser comme paramètre 'T' dans le type générique ou la méthode 'System.Nullable<T>'.

1 votes

L'erreur du compilateur vous donne la ligne de la définition de la fonction car c'est là que se trouve l'erreur.

207voto

Jon Skeet Points 692016

Vous devez ajouter un T : struct contrainte :

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

Sinon, C# essaiera de trouver ce que Nullable<T> et se rendre compte qu'elle ne possède pas déjà la contrainte requise par Nullable<T> lui-même. En d'autres termes, vous pourriez essayer d'appeler :

CoalesceMax<string>(...)

ce qui n'aurait pas de sens, puisque Nullable<string> n'est pas valable.

2 votes

Qu'en est-il avec le drapeau C# 8 Not nullable ?

1 votes

@kirinnee : Non, parce que Nullable<T> a encore besoin T doit être un type de valeur non annulable, et non pas n'importe quel type non annulable.

16voto

Josh Petrie Points 4000

Le site Nullable<T> est soumis à une contrainte qui exige T pour être un type de valeur ( struct en C#). C'est pour ça que le compilateur vous parle de Nullable<T> et non pas votre fonction ou le site d'appel de cette fonction -- c'est la Nullable qui est la cause première de l'erreur, ce qui est en fait plus utile que si le compilateur pointait simplement vers votre fonction et disait "ce n'est pas bon, réparez-le !". (Imaginez si CoalesceMax a utilisé plusieurs génériques et a violé la contrainte d'un seul d'entre eux. Il est plus utile de savoir quel générique a vu sa contrainte violée que de savoir simplement qu'une ou plusieurs contraintes de la section CoalesceMax ont été brisées).

La solution consiste à faire de votre T et de leurs T compatibles en introduisant la même contrainte. Cela se fait en ajoutant l'élément struct qui doit venir avant toutes les contraintes d'interface/nouvelles contraintes :

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

6voto

SLaks Points 391154

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

Cependant, vous ne limitez pas le type d'informations que vous pouvez utiliser. T donc ça pourrait finir par être Nullable<Form> ce qui est évidemment invalide.

Vous devez modifier la contrainte en where T : struct, IComparable afin de garantir que T ne peut être qu'un type de valeur.

2voto

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X