2013-06-13 34 views
51

Ho il seguente metodo generico, ma VS mi dà un errore di compilazione su questo. (Operatore '??' non può essere applicato a operandi di tipo 'T' e 'T')Operatore '??' non può essere applicato agli operandi di tipo "T" e "T"

public static T Method<T>(T model) where T : new() 
{ 
    var m = model ?? new T(); 
} 

Ha qualcuno ha qualche idea del perché?

Modifica: È possibile che T possa essere una struct nel mio caso e una struct è un tipo non annullabile?

risposta

53

Si dovrebbe aggiungere class vincolo:

public static T Method<T>(T model) where T : class, new() 
{ 
    var m = model ?? new T(); 

    return m; 
} 

E si dovrebbe tornare m troppo!

Nota: Come @KristofDegrave menzionato nel suo commento, la ragione per cui dobbiamo aggiungere class vincolo è perché T può essere un tipo di valore, come int e dal ?? operatore (null-coalescenza) controllare i tipi che possono essere NULL , quindi dobbiamo aggiungere il vincolo class per escludere i tipi di valore.

Modifica: la risposta di Alvin Wong riguardava anche il caso dei tipi nullable; quali sono in realtà le strutture, ma possono essere degli operandi ?? operatore. Tieni presente che lo Method restituirà null senza la versione sovraccaricata di Alvin, per i tipi nullable.

+0

perché dovrebbe restituire m? Invece di restituire il modello ?? nuovo T(); 'ho pensato che il risultato sarebbe stato lo stesso? – WiiMaxx

+2

Ovviamente sono uguali! Ma nella domanda viene usato il primo. È solo che ho menzionato. –

+3

È possibile che T possa essere una struct nel mio caso e una struct è un tipo non annullabile? –

8

È necessario specificare che il tipo di T è una classe con un vincolo sul tipo generico:

public static T Method<T>(T model) where T : class, new() 
{ 
    return model ?? new T(); 
} 
4

Dal T può essere di qualsiasi tipo, non v'è alcuna garanzia che T avrà una statica ?? operatore o che il tipo T è nullable.

?? Operator (C# Reference)

Il ?? l'operatore è chiamato operatore a coalescenza nulla e viene utilizzato per definire un valore predefinito per i tipi di valori nullable o i tipi di riferimento .

83

?? è l'operatore a coalescenza nulla. Non può essere applicato a tipi non annullibili. Poiché T può essere qualsiasi cosa, può essere un int o un altro tipo primitivo, non annullabile.

Se si aggiunge la condizione where T : class (deve essere specificata prima di new()) forza T come istanza di classe, che è nullable.

+0

Non ritiene la nuova() condizione di forza T essere un tipo nullable? –

+3

@KristofDegrave no new() significa solo che ci sarà un construtor vuoto – WiiMaxx

+0

È possibile che T possa essere una struct nel mio caso e che una struct sia un tipo non annullabile? –

0

model ?? new T() significa model == null ? new T() : model. Non è garantito che il modello non sia annullabile e che == non possa essere applicato per null e un oggetto non annullabile. Cambiare il vincolo su where T : class, new() dovrebbe funzionare.

0

Contrassegna T come "classe" e sei a posto.

4

Per qualche motivo l'operatore ?? non può essere utilizzato su tipi non nullable, anche se si suppone che sia equivalente a model == null ? new T() : model, e si sei ammessi un confronto NULL con un tipo non nullable.

è possibile ottenere esattamente quello che stai cercando, senza vincoli aggiuntivi utilizzando l'operatore ternario, invece, o un'istruzione if:

public static T Method<T>(T model) where T : new() 
{ 
    var m = model == null ? new T() : model; 
} 
+0

Questo non riesce a gestire i tipi 'Nullable <>'. Restituisce 'null' quando' model' è 'null'. –

+1

@AlvinWong Bene, 'var m = new int?()' Dovrebbe essere 'null'. Per i tipi di valore, 'new T()' è simile a (se non esattamente uguale a) 'default (T)'. Se vuoi inizializzare i tipi nullable con qualcosa di diverso dal risultato del costruttore predefinito, allora questo codice è inadeguato, ma quella non era la domanda dell'OP. –

31

molti hanno sottolineato già che l'aggiunta del vincolo class per il generico risolverà il problema

Se si desidera che il metodo sia applicabile agli Nullable<T> troppo, è possibile aggiungere un sovraccarico per esso:

// For reference types 
public static T Method<T>(T model) where T : class, new() 
{ 
    return model ?? new T(); 
} 

// For Nullable<T> 
public static T Method<T>(T? model) where T : struct 
{ 
    return model ?? new T(); // OR 
    return model ?? default(T); 
} 
+0

Tnx per indicarlo, ma non ho bisogno di supportarlo per i valori struct :) –

+10

@ KristofDegrave Basta sottolineare per completezza. Qualcun altro potrebbe averne bisogno! :) –

Problemi correlati