2009-05-06 4 views
35

Ho cercato delle indicazioni su questo perché il concetto è stato introdotto in .net 2.0.Perché non dovrei usare sempre i tipi nullable in C#

Perché dovrei voler utilizzare tipi di dati non annullabili in C#? (Una domanda migliore è perché non scegliere i tipi annullabili per impostazione predefinita e utilizzare solo tipi non annullabili quando ciò ha un significato esplicito.)

C'è un colpo "significativo" alle prestazioni nella scelta di un tipo di dati nullable su peer non annullabile?

Preferisco di gran lunga controllare i miei valori rispetto a null anziché Guid.empty, string.empty, DateTime.MinValue, < = 0, ecc. E per lavorare con i tipi nullable in generale. E l'unica ragione per cui non scelgo più spesso i tipi nullable è la sensazione di prurito nella parte posteriore della mia testa che mi fa pensare che sia più che retrocompatibile che costringe quel qualcosa in più '?' carattere per consentire esplicitamente un valore nullo.

C'è qualcuno là fuori che sempre (quasi sempre) sceglie tipi nullable anziché tipi non annullibili?

Grazie per il vostro tempo,

+0

Jon Skeet è corretto su System.Nullable che è una struttura.Quindi verrà assegnato allo stack e non all'heap. –

+3

La domanda sul colpo di prestazione può essere risolta solo da te; sei quello che sa cosa significa "significativo" per i tuoi clienti. Ma l'hit dovrebbe essere minimo - un int nullo è praticamente lo stesso di un int più un bool flag che indica se è nullo; il tipo Nullable è solo un modo conveniente per impacchettare l'int con il flag. –

risposta

46

Il motivo per cui non si dovrebbe usare sempre tipi nullable è che a volte si è in grado di garantire che un valore sarà inizializzato. E dovresti provare a progettare il tuo codice in modo che questo avvenga il più spesso possibile. Se non è possibile che un valore possa essere non inizializzato, non c'è motivo per cui null dovrebbe essere un valore legale per esso. Come un esempio molto semplice, si consideri questo:

List<int> list = new List<int>() 
int c = list.Count; 

Questo è sempre valido. Non esiste alcun modo in cui c potrebbe essere non inizializzato. Se è stato trasformato in un int?, si potrebbe effettivamente dire ai lettori del codice "questo valore potrebbe essere nullo. Assicurati di controllare prima di usarlo". Ma sappiamo che questo non può mai accadere, quindi perché non esporre questa garanzia nel codice?

Hai perfettamente ragione nei casi in cui un valore è facoltativo. Se abbiamo una funzione che può o non può restituire una stringa, restituire null. Non restituire string.Empty(). Non restituire "valori magici".

Ma non tutti i valori sono opzionali. E rendere tutto facoltativo rende il resto del codice molto più complicato (aggiunge un altro percorso di codice che deve essere gestito).

Se è possibile garantire espressamente che questo valore sarà sempre valido, allora perché buttare via queste informazioni? Questo è quello che fai rendendolo un tipo nullable. Ora il valore può o non può esistere e chiunque utilizzi il valore dovrà gestire entrambi i casi. Ma tu sai che solo uno di questi casi è possibile in primo luogo. Così gli utenti del tuo codice sono un favore e riflettono questo fatto nel tuo codice. Qualsiasi utente del tuo codice può quindi fare affidamento sul fatto che il valore sia valido e deve gestire solo un singolo caso piuttosto che due.

+0

Questa è davvero una buona risposta alla domanda, ma mi fa venir voglia di rivederla. Perché non dovrei utilizzare sempre i tipi Nullable per le proprietà della classe dominio bussiness nelle applicazioni aziendali? Quale penso che probabilmente possa la maggior parte del tempo. Grazie per il tuo tempo. –

+2

Penso che si applichino le stesse regole pratiche. Puoi garantire che la proprietà sarà sempre valida? (Probabilmente il tuo oggetto avrà sempre un ID, quindi non è necessario renderlo nullable.) Ma altre proprietà potrebbero o meno esistere, a seconda dello stato dell'oggetto. Ma ricorda che * se * puoi rendere un valore non annullabile, questo rende molto più piacevole lavorare con il futuro, perché gli utenti non devono controllarlo con null, quindi vedere se è possibile garantire che la proprietà sia valida e, in caso affermativo, non renderla nullable. – jalf

+5

Non sarebbe bello se ottenessimo la funzione SpeC# per dichiarare i tipi di riferimento come non annullabile? 'Stringa!' Sarebbe quindi una stringa che non può essere nullo. –

9

perché è scomodo dover sempre controllare se il tipo nullable è null.

Ovviamente ci sono situazioni in cui un valore è veramente opzionale, e in quei casi ha senso usare un tipo nullable piuttosto che numeri magici, ecc, ma dove possibile proverei ad evitarli.

// nice and simple, this will always work 
int a = myInt; 

// compiler won't let you do this 
int b = myNullableInt; 

// compiler allows these, but causes runtime error if myNullableInt is null 
int c = (int)myNullableInt; 
int d = myNullableInt.Value;  

// instead you need to do something like these, cumbersome and less readable 
int e = myNullableInt ?? defaultValue; 
int f = myNullableInt.HasValue ? myNullableInt : GetValueFromSomewhere(); 
+0

Immagino che questo sia il mio punto. Potenzialmente myNonNullableInt non sarà ancora stato impostato, e avrà il valore 0 predefinito al suo interno che è altrettanto non valido per il mio dominio aziendale di null. Quindi devo comunque fare un controllo. E preferisco myNullableInt! = Null a myNonNullableInt> 0 –

+0

Anche per scope non locali ha senso usare solo i tipi nullable dove appropriato: se un valore non può mai essere effettivamente nulla allora perché dichiararlo come nullable, cioè ogni pezzo di codice che si occupa di quel tipo deve fare controlli extra, ecc. – LukeH

0

Io tendo ad usare i tipi Nullable ovunque hanno un senso - non mi preoccupano le prestazioni fino a che non è un problema, allora io preparo le poche aree in cui è e da fare con esso.

Tuttavia, trovo anche che, in generale, la maggior parte dei miei valori finisce per essere non annullabile. In effetti, ci sono molte volte che mi piacerebbe davvero un NotNullable che posso usare con i tipi di riferimento per scoprire un problema nullo quando ottengo il null, non più tardi quando provo ad usarlo.

2

Penso che i progettisti linguistici ritengano che "i tipi di riferimento siano annullabili per impostazione predefinita" sia stato un errore e che il non nullable sia l'unico valore predefinito valido e che sia necessario attivare la nullità. (Questo è come è in molti moderni linguaggi funzionali.) "Null" è di solito un mucchio di problemi.

+0

Si dice che i progettisti linguistici vogliono "allontanarsi" dalla nullità, ma in realtà hanno AGGIUNTO il nullability ai tipi di valore, che prima non potevano essere nulli. E i tipi di riferimento sono ancora nulli per impostazione predefinita, senza possibilità di disattivazione. Non capisco il tuo ragionamento – Lucas

+1

Ecco un modo migliore per caratterizzare la posizione di alcuni progettisti di linguaggi. Abbiamo due tipi di tipi: tipi di valore e tipi di riferimento. Abbiamo due tipi di tipi: tipi nullable e tipi non annullibili. Abbiamo iniziato con un sistema di tipi in cui tutti i tipi di riferimento erano annullabili e tutti i tipi di valore non erano annullabili. Abbiamo quindi aggiunto tipi di valori nullable. Ma aggiungere tipi di riferimento non annullabili è estremamente difficile ora. Sarebbe stato meglio progettare il sistema dei tipi per consentire tutte e quattro le possibilità in primo luogo. –

+0

Sì, quello che Eric ha detto è fantastico. Aggiungerò che il nullability per i tipi di valore è una vittoria specifica per alcuni scenari di interoperabilità (con, ad esempio, i database SQL). Ma il non-nullability per la maggior parte dei tipi è una vittoria generale per la maggior parte del codice da una prospettiva generale di ingegneria del software. – Brian

3

Lei sembra avere 2 domande differenti ...

Perché mai dovrei voler utilizzare i tipi di dati non-nullable in C#?

Semplice, perché i dati di tipo valore su cui si basa è garantito dal compilatore per avere effettivamente un valore!

Perché non scegliere i tipi nullable per impostazione predefinita e utilizzare solo tipi non annullibili quando ciò ha un significato esplicito?

Come già detto da Joel, un tipo può essere nullo solo se si tratta di un tipo di riferimento. I tipi di valore sono garantiti dal compilatore per avere un valore. Se il tuo programma dipende da una variabile per avere un valore, allora questo è il comportamento che vorresti non scegliendo un tipo nullable.

Ovviamente, quando i tuoi dati provengono da qualsiasi luogo diverso dal tuo programma, tutte le scommesse sono disattivate. Il miglior esempio è da un database. I campi del database possono essere null, quindi è preferibile che la variabile del programma imiti questo valore, non solo creare un valore "magico" (vale a dire -1, 0 o qualsiasi altra cosa) che "rappresenta" null. Lo fai con tipi nullable.

+0

Come menzionato nelle altre risposte/commenti, i tipi nullable * sono tipi di valore * ma non è garantito che abbiano un valore. (Ecco a cosa serve la proprietà HasValue!) – LukeH

+0

Va bene, intendeva "tipi di valori non annullabili" :) – Lucas

0

Anche se i valori nulli possono essere conveniente per l'utilizzo come "non-inizializzato-ancora" o "non specificato" valori, rendono il codice più complesso, soprattutto perché si sta sovraccaricando il significato di null così come la variabile (numero-o-nullo vs. solo-un-numero).

I valori NULL sono preferiti da molti progettisti di database e programmatori di database SQL ma con un piccolo cambiamento nel pensare al problema è possibile eliminare valori nulli e in realtà avere un codice più semplice e più affidabile (ad esempio, non preoccuparsi di NullReferenceException s) .

C'è in realtà una grande richiesta per un "T!" operatore che rende qualsiasi tipo di riferimento non annullabile, simile a come "T?" rende nullable i tipi di valore, e Anders Hejlsberg, l'inventore di C#, ha voluto che avesse incluso l'abilità.

Vedi anche la questione, Why is “null” present in C# and java?

0

L'unica volta che un tipo Nullable deve mai essere utilizzato, è nel caso in cui un determinato campo in una tabella del database richiede assolutamente che un null venga inviato o ricevuto dall'applicazione a un certo punto. Anche in questo caso, si dovrebbe sempre cercare di trovare un modo per utilizzare il tipo Nullable. Bool non è sempre il tuo migliore amico.