Aiuto con C # generics error - "Il tipo 'T' deve essere un tipo di valore non annullabile"


100

Sono nuovo in C # e non capisco perché il codice seguente non funziona.

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

Fornisce il seguente errore durante la compilazione:

Il tipo "T" deve essere un tipo di valore non nullable per poterlo utilizzare come parametro "T" nel tipo o metodo generico "System.Nullable <T>"

1
L'errore del compilatore ti dà la riga della definizione della funzione perché è lì che si trova l'errore.
SLaks

Risposte:


180

Devi aggiungere un T : structvincolo:

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

Altrimenti C # proverà a capire cosa Nullable<T>significa e si renderà conto che non ha già il vincolo richiesto da Nullable<T>solo. In altre parole, potresti provare a chiamare:

CoalesceMax<string>(...)

che non avrebbe senso, in quanto Nullable<string>non è valido.


16

Il Nullable<T>tipo ha un vincolo su di esso che richiede Tdi essere un tipo di valore ( structin C #). Ecco perché il compilatore ti sta parlando Nullable<T>e non della tua funzione o del sito di chiamata di quella funzione: è la Nullableclasse che è la causa principale dell'errore, quindi questo è effettivamente più utile che se il compilatore ha semplicemente puntato alla tua funzione e ha detto "questo non è giusto, aggiustalo!" (Immagina di CoalesceMaxusare diversi generici e di violare il vincolo su uno solo di essi: è più utile sapere quale generico ha infranto il suo vincolo piuttosto che sapere semplicemente che uno o più vincoli CoalesceMaxsono stati infranti).

La soluzione è rendere il tuo Te il loro Tcompatibili introducendo lo stesso vincolo. Questo viene fatto aggiungendo il structvincolo, che deve precedere ogni interfaccia / nuovi vincoli:

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

6

Il tuo metodo generico utilizza un file Nullable<T>.

Tuttavia, non stai limitando il tipo di T, quindi potrebbe finire per essere Nullable<Form>, il che ovviamente non è valido.

È necessario modificare il vincolo in where T : struct, IComparableper assicurarsi che Tpossa essere solo un tipo di valore.


2

Non esattamente una risposta all'OP, ma poiché questa era la prima cosa che è comparsa su Google per lo stesso messaggio di errore, ho dovuto aggiungere il vincolo alla definizione della mia classe, piuttosto che al mio metodo, ad es.

public class MyClass<T> where T : struct
{
    public void MyMethod(T? value)
    {
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.