Qual è la buona pratica per i controlli di riferimento null?

Qual è il modo più efficiente per verificare riferimenti null sugli oggetti? Ho visto vari esempi di codice che hanno diversi modi di controllare il seguente che è il più efficiente o quello che è considerato la migliore pratica da usare?

Object.ReferenceEquals(item, null) item == null item != null Object.Equals(item, null) 

Grazie

  1. Object.ReferenceEquals(item, null) confronta i riferimenti ed è uguale a item == null .
  2. Object.Equals(item, null) confronta i riferimenti per i tipi di riferimento e bit per i tipi di valori, ma in reflector è uguale a (item == null) || ((item != null && null != null) && item.Equals(null)) (item == null) || ((item != null && null != null) && item.Equals(null)) .
  3. item != null codice item != null non sempre è uguale a !(item == null) , ma ovviamente il risultato dovrebbe essere uguale.
  4. item == null codice item == null non è uguale a null == item , è simile a typeof(item).Equals(object) e object.Equals(typeof(item)) chiamate di metodo.

Differisce perché puoi eseguire l’override != , == , != . Utilizzare metodi con implementazione nota, null == item è meglio codificare, ma più difficile da leggere. Object.ReferenceEquals(null, item) potrebbe essere più veloce o meno.

PS usa anche string.IsNullOrEmpty (item)

Per il confronto con null , userei == o != Sempre, perché per null dovrebbe sempre dare lo stesso risultato di ReferenceEquals ed Equals comunque (quindi non c’è bisogno del codice extra).

Modifica : È vero che == potrebbe essere sovrascritto per dare un risultato errato per null (vale a dire, true ) ma ciò significa che l’override è bacato. Per rendere leggibile il codice, rimango con == e != .

Come extra, non dimenticare i contratti di codice in .NET 4.0!

 System.Diagnostics.Contracts.Contract.Requires(item != null); 

Che non è solo bello e chiaro, ma consente il controllo del tempo di compilazione. Vedi i contratti di codice in msdn.

ReferenceEquals equivale a (object)o1==(object)o2 . Potrebbe essere più veloce di o1==o2 se l’operatore di uguaglianza è sovraccarico. Object.Equals è probabilmente un po ‘più lento.

La differenza tra == e != Non è la prestazione, ma come dovrebbe essere il tuo programma. Possono essere un po ‘più lenti se l’operatore == e != È sovraccarico.

Ma non credo che la differenza di prestazioni tra loro sia importante. Sceglierei quello che è più facile da leggere. E questo di solito è == o != .

Se lancio un’eccezione, di solito uso == come in:

 if(o == null) throw new ...; 

Se null risulta in un no-op allora di solito != È appropriato

 if(x != null) { ... } 

Io uso sempre

 item != null 

ma questo è più difficile da leggere di

 item == null 

Object.ReferenceEquals viene utilizzato per verificare se due oggetti sono la stessa istanza.

1)

 Object.ReferenceEquals(item, null) 

Questo è un buon modo. Non così conciso come mi piacerebbe, ma comunque fantastico e ti dice esattamente l’intento.

2)

 item == null item != null 

Non c’è niente di sbagliato in questo ( che è il più elegante ) se sei sicuro == e successivamente != È sovraccaricato correttamente. È facile da scrivere (sovraccarico) operatori di uguaglianza ctriggers (e spesso fatto). Ma il vero problema è quando si tenta di sovraccaricare l’operatore == in una class (diciamo di valore semantico). Non è ansible utilizzare == per i controlli nulli all’interno di == funzione di overload della class poiché ciò causerà una ricorsione infinita . Per avere uno stile coerente, mi baso su qualcos’altro.

3)

 Object.Equals(item, null) 

Anche in questo caso internamente fa un ReferenceEquals quindi non c’è molto senso, ma se semanticamente ha più senso per te, allora vai con questo.

4)

Il mio approccio è fare

 (object)item == null 

su cui mi affido all’operatore di uguaglianza di un object che non può sbagliare. Non è così leggibile, quindi avvolgo solo un metodo di estensione personalizzato e un sovraccarico:

 public static bool IsNull(this T obj) where T : class { return (object)obj == null; } public static bool IsNull(this T? obj) where T : struct { return !obj.HasValue; } 

Ha più senso dal momento che DBNull confrontarmi con DBNull troppo spesso. Quindi ora ho uno stile coerente dappertutto!

 public static bool IsNull(this T obj) where T : class { return (object)obj == null || obj == DBNull.Value; } 

(Non togliere il cast (object) poiché è ciò che impedirà la ricorsione infinita quando si esegue il sovraccarico == come indicato in precedenza)

Inoltre il vincolo previene IsNull sui tipi di valore. Ora è dolce come chiamare

 object obj = new object(); Guid? guid = null; bool b = obj.IsNull(); // false b = guid.IsNull(); // true 2.IsNull(); // error 

Ho anche trovato (object)item == null è molto molto molto più veloce di Object.ReferenceEquals(item, null) o object.Equals(,) per quella materia, ma solo se è importante (sto lavorando a qualcosa dove devo micro-ottimizzare tutto!).

Per visualizzare una guida completa sull’implementazione dei controlli di uguaglianza, vedere Che cos’è “Best Practice” per confrontare due istanze di un tipo di riferimento?

I primi 2 sono uguali in modo efficace.

L’ultimo tuttavia non esegue solo un controllo di riferimento e non deve essere utilizzato per il controllo nullo.