2010-07-19 8 views
10

Ho appena iniziato a scrivere su un componente in cui ho trovato che potrebbe essere utile dichiarare alcune delle proprietà nullable, invece di lasciarli ricorrere ai valori predefiniti. Tuttavia, mi sono reso conto che non avevo mai usato prima la sintassi non-nullable-type? o il tipo Nullable<T>, quindi probabilmente ci sono alcuni trucchi che presto salteranno e mi morderanno. Quindi ...Gotchas quando si utilizza Nullable <T> in C# 4

  • Quali sono i maggiori grattacapi quando si utilizza Nullable<T> e la stenografia ? sintassi?

  • Come lavoro intorno a loro?

  • Quali sono i maggiori vantaggi/nuove possibilità che sono disponibili per me quando inizio a utilizzarli?

+9

scrivere il codice. Torna quando esplode. Non è scienza missilistica. –

+3

@Hans, non sono d'accordo: non è una brutta cosa cercare di anticipare i problemi ... Sono sicuro che le risposte sarebbero utili a molte persone –

+0

@Closers: mi rendo conto che dovrò tornare alla comunità quando ho un problema "reale", ma dal momento che questo è un concetto completamente nuovo, non pensavo che mi avrebbe fatto male ricevere un aiuto per esplorare il terreno. Se questo concetto non è molto difficile, forse sono troppo cauto - ma potrebbe essere stata una di quelle aree in cui sei destinato a commettere errori da principiante e dove potrebbero essere molto difficili da individuare. La risposta di Mark Byers è un eccellente esempio di ciò che stavo cercando. –

risposta

18

Un getcha comune sta tentando di assegnare a una variabile nullable con un'espressione condizionale come segue:

bool useDefault = true; 
int defaultValue = 50; 
int? y = useDefault ? defaultValue : null; 

A prima vista questo potrebbe apparire come dovrebbe funzionare, ma in realtà si dà un errore di compilazione:

 
Type of conditional expression cannot be determined because there is no 
implicit conversion between 'int' and '<null>' 

Soluzione: aggiungere un cast di uno o di entrambi i possibili esiti:

int? y = useDefault ? defaultValue : (int?)null; 

Meno comunemente visto: Normalmente è lecito ritenere che per gli interi e a <= 5!(a > 5) sono equivalenti. Questa ipotesi non è vera per gli interi nullable.

int? x = null; 
Console.WriteLine(x <= 5); 
Console.WriteLine(!(x > 5)); 

risultati:

 
False 
True 

Soluzione: gestire il caso nullo separatamente.


Ecco un altro leggera variazione di quanto sopra:

int? y = null; 
int? z = null; 
Console.WriteLine(y == z); 
Console.WriteLine(y <= z); 

uscita:

 
True 
False 

Così y è uguale a z, ma non è minore o uguale a z.

Soluzione: Anche in questo caso, il trattamento del caso null separatamente può evitare sorprese.

+0

Entity Framework mi ha insegnato molto sui tipi nullable – msarchet

1

si può fare .HasValue per verificare se la variabile è nulla

si può fare

myvar = nullablevar ?? defaultvalue; //will set defaultvalue if nullablevar is null 

e di più, non è nuovo a C# 4

read this for more information

+0

Non proprio un "trucco" ma MOLTO utile sapere –

0

Attualmente non utilizzo 4.0, ma in 2.0 ho il problema che, come la maggior parte dei generici, int? non può essere de-serializzato facilmente. Forse 4.0 è più intelligente con Reflection, ma le utilità di serializzazione XML predefinite non sono in grado di leggerlo. È abbastanza fastidioso.

+0

Non so se era diverso in 2.0, ma in 4.0 la serializzazione di tipi generici in XML non è affatto un problema. .. serializzare un risultato 'Foo ' in un elemento '' in XML –

+0

In 2.0, ottengo un errore di riflessione dal deserializzatore XML (utilizzo solo il valore predefinito) utilizzando qualsiasi proprietà o campo generico. Devo stringare [] o ArrayList perché l'elenco non serializza/deserializza. Se questo è fissato in 4.0, il mio cuore canterà di gioia. Lavorare sul codice legacy fa schifo. –

0

Impostare il valore predefinito inconsciamente durante l'utilizzo di nullable. Ho visto questo alcune volte. Per esempio.

int? localVar = 0; 
// do something .. 
if (localVar.HasValue) 
    _myMemberValue = localVar.Value; 

Il localvar è mai nullo perché era inizializza con un valore tale test è HasValue alwasy vero e _myMemberValue potrebbe erroneamente assegnato con il valore corretto.

- Editied, per aggiungere ulteriori commenti ----

dimenticato di dire. Uno dei principali vantaggi che ho visto è quello di utilizzare il campo per rappresentare il campo Nullable nel database. Questo viene generato automaticamente anche se si utilizzano Linq ed EF. Ma tradizionalmente prima di Nullable, è un lavoro manuale e un errore incline a gestire l'aggiornamento del campo e decidere su quando impostarlo con un valore o su null.

1

Nullable<T> è un tipo di valore speciale. Potrebbe aiutarti se capisci come funziona davvero. Ci sono alcune cose sottili che non sono immediatamente ovvie. Ho bloggato circa here.

Trucchi reali - non molti. Quasi il più grande è che il cast esplicito potrebbe lanciare un InvalidOperationException (e non NullReferenceException). Il compilatore dovrebbe guidarti per eventuali problemi che potrebbero sorgere.

1

Nullable<T> tipi un po 'inusuali; non sono (in senso stretto) né valori né tipi di riferimento, ma qualcosa di strano nel mezzo. In particolare, il boxing/unboxing e lo typeof hanno regole speciali, quindi i risultati sono meno imprevisti.

Per i dettagli, raccomando il libro di Jon Skeet C# in Depth. Se non lo possiedi già, dovresti. :)

10

Le persone sono spesso sorprese dal fatto che non esiste un valore di tipo nullable inserito. Se dici:

int? x = 123; 
int? y = null; 
int z = 456; 
object xx = x; 
object yy = y; 
object zz = z; 

si potrebbe pensare che, dal momento zz contiene un int boxed, che XX e YY contengono inscatolato int nullable. Loro non. xx contiene un int inscatolato. yy è impostato su null.

1

Uno degli usi migliori è che si adatta abbastanza bene ai campi del database nullable. Tenendolo presente, si desidera utilizzarlo come si farebbe con un campo nullo in un database.

Cioè, un valore nullo non è "altro" - significa sconosciuto, o incalcolabile in questo momento, o quello dato altri valori in questo oggetto/record, non ha senso che questo sia un valore .La vostra situazione suona come esso è valido - le preferenze degli utenti può essere NULL, e valori effettivi saranno

actualValue = userValue ?? defaultValue; 

Il ?? è l'operatore nulla coalesce - quanto sopra è equivalente al seguente:

actualValue = userValue.HasValue ? userValue : defaultValue; 

o

actualValue = (userValue != null) ? userValue : defaultValue; 

La tentazione vedo gente dà in più spesso sta usando bool? come bandiera tri-state. Questo non ha senso, perché non c'è una terza possibilità in vero/falso/???. Altri che leggono il tuo codice dovranno scavare attraverso i commenti (il migliore dei casi) per scoprire che il vero significava usare il testo blu, il falso significava il testo rosso e null significava il testo verde. Usa le enumerazioni per questo.

Questo è il più grande trappola vedo persone cadono in - a parte quello, solo abituarsi a controllare se i vostri nullables sono nulli - sia attraverso il confronto su null o utilizzando .HasValue

+0

+1 per la nota su 'bool?' Come bandiera a tre stati =) –

Problemi correlati