Verifica se un oggetto è nullo in C #


226

Vorrei impedire ulteriori elaborazioni su un oggetto se è nullo.

Nel seguente codice controllo se l'oggetto è nullo da uno dei due:

if (!data.Equals(null))

e

if (data != null)

Tuttavia, ricevo un NullReferenceExceptionat dataList.Add(data). Se l'oggetto era nullo, non avrebbe mai dovuto nemmeno entrare nello ifstato!

Pertanto, sto chiedendo se questo è il modo corretto di verificare se un oggetto è null:

public List<Object> dataList;
public  bool AddData(ref Object data)
    bool success = false;
    try
    {
        // I've also used "if (data != null)" which hasn't worked either
        if (!data.Equals(null))
        {
           //NullReferenceException occurs here ...
           dataList.Add(data);
           success = doOtherStuff(data);
        }
    }
    catch (Exception e)
    {
        throw new Exception(e.ToString());
    }
    return success;
}

Se questo è il modo corretto di verificare se l'oggetto è nullo, cosa sto facendo di sbagliato (come posso impedire ulteriori elaborazioni sull'oggetto per evitare NullReferenceException)?


13
Dovresti anche usare throw e;controthrow new Exception(e.ToString());
Nix il

17
in C # dovresti sempre usare != nullnei tuoi controlli null. .Equalsgenererà sempre un'eccezione se l'oggetto è null.
Kyle Trauberman,

42
@Nix: throw e;non è molto meglio. throw;, d'altra parte ...
Jon,

4
@developer: e.ToString()produrrà una stringa che include non solo il messaggio di errore, ma anche quelli di tutti InnerExceptionse la traccia dello stack. Quindi è una specie di messaggio di eccezione molto pesante. Se (giustamente!) Vuoi conservare queste informazioni e mantenerne la posizione, usa semplicemente throw;.
Jon,

14
Il tentativo / cattura non fa nulla al momento. Tutti dicono semplicemente di usare "lancio" ma se non si sta facendo nulla con l'eccezione ma rilanciandolo, perché avere un blocco try / catch? Di solito si rilevano delle eccezioni per gestirle con garbo, ripulire le risorse (meglio con la clausola "finally") o eseguire una sorta di registrazione prima di respingere l'eccezione. Nessuno di questi sta accadendo in questo codice, quindi non c'è bisogno di provare / catturare affatto.
David Peterson,

Risposte:


252

Non è dataquello null, ma dataList.

Devi crearne uno con

public List<Object> dataList = new List<Object>();

Ancora meglio: dal momento che è un campo, fallo private. E se non c'è nulla che ti impedisce, fallo anche tu readonly. Solo buone pratiche.

A parte

Il modo corretto di verificare la nullità è if(data != null). Questo tipo di controllo è onnipresente per i tipi di riferimento; Nullable<T>ignora anche l'operatore di uguaglianza per essere un modo più conveniente di esprimere nullable.HasValuequando si verifica la nullità.

Se lo fai if(!data.Equals(null)), otterrai un NullReferenceExceptionif data == null. Che è un po 'comico da quando evitare questa eccezione è stato l'obiettivo in primo luogo.

Stai anche facendo questo:

catch (Exception e)
{
    throw new Exception(e.ToString());
}

Questo sicuramente non va bene. Posso immaginare di averlo messo lì solo per poter entrare nel debugger mentre sei ancora all'interno del metodo, nel qual caso ignora questo paragrafo. Altrimenti, non prendere eccezioni per niente. E se lo fai, ricodificali usando solo throw;.


5
Ho visto anche Object.ReferenceEquals (obj, null) per questo scopo. Per evitare le sostituzioni di uguaglianza?
Luca

2
@LucaPiccioni L'ho usato per prevenire lamentele sul valore quando si usano i generici: geekality.net/2009/11/13/generics-and-checking-for-null
Svish

4
Io preferisco null != data. Mettere la costante per prima trasforma il refuso di bonehead null = datain un errore del compilatore, piuttosto che un incarico involontario. (Funziona anche per ==.)
jpmc26

6
@ jpmc26: In C # if (data = null)è già un errore di compilazione, quindi anche se ci sono voluti decenni per arrivarci, non c'è più bisogno di fare attenzione. Anche i compilatori C ++ genereranno facilmente un avviso su possibili assegnazioni involontarie per quel codice.
Jon,

Luca, puoi anche evitare le sostituzioni di uguaglianza lanciando "oggetto" nel test. Allo stesso modo, questa risposta dovrebbe invece affermare questo: "if ((object) data! = Null)" poiché evita errori quando l'uguaglianza è stata superata.
DAG,

81

in C #> 7.0 utilizzare

if (obj is null) ...

Questo ignorerà qualsiasi == o! = Definito dall'oggetto (a meno che ovviamente tu non voglia usarli ...)

Per uso non nullo if (obj is object)(o if (!(obj is null)))


1
Mi chiedo c'è un "non è nullo"? (direbbe Pitone obj is not null)
vedi il

1
Perché è meglio di if (obj! = Null) che è più leggibile
Orn Kristjansson

38
Vorrei che implementassero if (obj aint null):(
Nick Bull,

10
Perché non è nullo c'èif (obj is object)
yatskovsky,

3
@OrnKristjansson perché! = E == possono essere ignorati.
mitchellJ,

61

C # 6 ha un controllo null monadico :)

prima:

if (points != null) {
    var next = points.FirstOrDefault();
    if (next != null && next.X != null) return next.X;
}   
return -1;

dopo:

var bestValue = points?.FirstOrDefault()?.X ?? -1;

7
Perché "i commenti possono essere modificati solo per 5 minuti"? Che cosa? Ad ogni modo ... Mentre ci stavo arrivando, sono venuto qui alla ricerca di una sintassi migliore da esprimere result = myObject == null ? null : myObject.SomePropertye il tuo esempio mi ha suggerito di scrivere result = myObject?.SomeProperty. Uomo!! È subdolo. Adoro ancora programmare ...
Adam Cox,

27

Il tuo DataList è nullo in quanto non è stato istanziato, a giudicare dal codice che hai pubblicato.

Provare:

public List<Object> dataList = new List<Object>();
public  bool AddData(ref Object data)
bool success = false;
try
{
    if (!data.Equals(null))   // I've also used if(data != null) which hasn't worked either
    {
       dataList.Add(data);                      //NullReferenceException occurs here
       success = doOtherStuff(data);
    }
}
catch (Exception e)
{
    throw new Exception(e.ToString());
}
return success;

}


3
Inoltre, solo per aggiungere, se i dati sono null, non si arresta in modo anomalo, è possibile aggiungere null a un elenco <Oggetto>.
DaveShaw,

7
Ma provare a fare. Gli equi su un null genererebbero un'eccezione. Dovrebbe fare! = Null
glosrob il

@glosrob: Ah !! Che svista! Stavo pensando che NullReferenceException provenisse dall'oggetto .. non dall'elenco! Sono nuovo di c # e ho pensato che ci fosse un modo speciale per verificare la presenza di null in c #!
sviluppatore

Anche quello, ma ho visto Ed S. l'aveva coperto.
DaveShaw,

1
@DaveShaw: grazie per l'heads up. Voglio evitare che un oggetto null venga aggiunto per successive elaborazioni, quindi farò comunque un controllo. :)
sviluppatore

19

[Modificato per riflettere il suggerimento di @ kelton52]

Il modo più semplice è fare object.ReferenceEquals(null, data)

Poiché (null==data)NON è garantito il funzionamento:

class Nully
{
    public static bool operator ==(Nully n, object o)
    {
        Console.WriteLine("Comparing '" + n + "' with '" + o + "'");
        return true;
    }
    public static bool operator !=(Nully n, object o) { return !(n==o); }
}
void Main()
{
    var data = new Nully();
    Console.WriteLine(null == data);
    Console.WriteLine(object.ReferenceEquals(null, data));
}

produce:

Confronto '' con 'Nully'

Vero

falso


1
In realtà l'ho appena provato e l'osservazione "Il vantaggio implicito è che ignora eventuali sostituzioni che potrebbero essere presenti nella classe di dati, come" operator! = "." Non sembra essere vero.
Kelly Elton,

9

No, dovresti usare !=. Se dataè effettivamente nullo, il programma si arresterà in modo anomalo a NullReferenceExceptioncausa del tentativo di richiamare il Equalsmetodo null. Inoltre, tieni presente che, se desideri verificare specificamente l'uguaglianza di riferimento, dovresti utilizzare il Object.ReferenceEqualsmetodo in quanto non sai mai come Equalsè stato implementato.

Il programma si arresta in modo anomalo perché dataListè nullo poiché non viene mai inizializzato.


7

Il problema in questo caso non dataè null. È che dataListè di per sé nullo.

Nel punto in cui si dichiara dataListè necessario creare un nuovo Listoggetto e assegnarlo alla variabile.

List<object> dataList = new List<object>();

5

Oltre alla risposta @Jose Ortega , è meglio usare il metodo di estensione

 public static bool IsNull(this object T)
     {
        return T == null;
     } 

E usa il IsNullmetodo per tutti gli oggetti come:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }

1
Perché return T == null ? true : false;e non solo return T == null;?
md2perpe,

1
Non sono sicuro di essere d'accordo. Sembra strano chiamare un metodo su un oggetto per verificare se è nullo. Senza sapere che si trattava di un metodo di estensione, si potrebbe pensare che genererebbe un'eccezione di riferimento null.
Jamie Twells,

Posso confermare totalmente che Jamie è corretto - questo non funzionerà. Lo so perché ho avuto un momento critico e ho scritto un metodo di estensione simile: P Il codice ha sempre generato un'eccezione di riferimento null, assolutamente non andrà nel metodo di estensione.
James King,

In realtà voglio dire che puoi farlo con il metodo di estensione ... potrebbe essere che il codice abbia qualche problema e possa migliorare!
Ali,

È possibile chiamare un metodo di estensione su un oggetto null; devi solo confrontare T (in questo caso) con null per stare attento. Jamie ha ragione, però, sembra strano.
Tim Barrass,

3

A partire da C # 8 è possibile utilizzare il modello di proprietà 'vuoto' (con corrispondenza del modello ) per assicurarsi che un oggetto non sia nullo:

if (obj is { })
{
    // 'obj' is not null here
}

Questo approccio significa " se l'oggetto fa riferimento a un'istanza di qualcosa " (ovvero non è nullo).

Si può pensare a questo come l'opposto di: if (obj is null).... che tornerà vero quando l'oggetto non fa riferimento a un'istanza di qualcosa.

Per maggiori informazioni sugli schemi in C # 8.0 leggi qui .


3

A partire da C # 9 puoi fare

if (obj is null) { ... }

Per uso non nullo

if (obj is not object) { ... }

Se è necessario ignorare questo comportamento, utilizzare ==e di !=conseguenza.


2

Jeffrey L Whitledge ha ragione. Il tuo oggetto `dataList´ stesso è nullo.

C'è anche un altro problema con il tuo codice: stai usando la parola chiave ref, il che significa che i dati dell'argomento non possono essere nulli! Il MSDN dice:

Un argomento passato a un parametro ref deve prima essere inizializzato. Ciò differisce da out, i cui argomenti non devono essere inizializzati esplicitamente prima di essere passati

Inoltre, non è una buona idea usare generici con il tipo "Oggetto". I generici dovrebbero evitare il pugilato / unboxing e garantire anche la sicurezza del tipo. Se vuoi un tipo comune, rendi generico il tuo metodo. Alla fine il tuo codice dovrebbe apparire così:

public class Foo<T> where T : MyTypeOrInterface {

      public List<T> dataList = new List<T>();

      public bool AddData(ref T data) {
        bool success = false;
        try {
          dataList.Add(data);                   
          success = doOtherStuff(data);
        } catch (Exception e) {
          throw new Exception(e.ToString());
        }
        return success;
      }

      private bool doOtherStuff(T data) {
        //...
      }
    }

2

Come altri hanno già sottolineato, non è, datama piuttosto probabile dataListche lo sia null. In aggiunta a ciò...

catch- throwè un antipasto che quasi sempre mi fa venir voglia di vomitare ogni volta che lo vedo. Immagina che qualcosa vada in profondità in qualcosa che doOtherStuff()chiama. Tutto ciò che ottieni è un Exceptionoggetto, lanciato throwdentro AddData(). Nessuna traccia dello stack, nessuna informazione sulla chiamata, nessuno stato, niente di tutto per indicare la vera fonte del problema, a meno che tu non entri e cambi il tuo debugger per interrompere l'eccezione generata anziché l'eccezione non gestita. Se si stanno recuperando un'eccezione e appena ri-gettandolo in alcun modo , in particolare se il codice nel blocco try è in alcun modo non banale, fare da soli (e vostri colleghi, presente e futuro) un favore e buttare via l'intero try- catchblocco . Certo,throw;è meglio delle alternative, ma ti stai ancora dando (o chiunque altro sta cercando di correggere un bug nel codice) mal di testa completamente inutili. Questo non vuol dire che try-catch-throw sia necessariamente male di per sé, purché si faccia qualcosa di rilevante con l'oggetto eccezione che è stato lanciato all'interno del blocco catch.

Quindi ci sono i potenziali problemi di cattura Exceptionin primo luogo, ma questa è un'altra questione, soprattutto perché in questo caso particolare si lancia un'eccezione.

Un'altra cosa che mi sembra più che un po 'pericolosa è che datapotrebbe potenzialmente cambiare valore durante l'esecuzione della funzione, poiché stai passando per riferimento. Quindi il controllo null potrebbe passare ma prima che il codice riesca a fare qualsiasi cosa con il valore, viene cambiato, forse in null. Non sono positivo se questa è una preoccupazione o meno (potrebbe non esserlo), ma sembra che valga la pena di fare attenzione.


2
  public static bool isnull(object T)
  {
      return T == null ? true : false;
  }

uso:

isnull(object.check.it)

Uso condizionale:

isnull(object.check.it) ? DoWhenItsTrue : DoWhenItsFalse;

Aggiornamento (un altro modo) aggiornato il 31/08/2017. Grazie per il commento.

public static bool isnull(object T)
{
    return T ? true : false;
}

5
cond ? true : false;è completamente equivalente a solo cond. Questo non aggiunge nulla.
lericson,

Mi dispiace ma se si controlla la funzione deve restituire un valore bool. Sto facendo il formalismo. Quindi ricontrolla
Jose Ortega il

3
intende return T == null;anche restituire un valore booleano!
MQoder,

So cosa sta dicendo. ty
Jose Ortega,

1
Invece di return T == null ? true : false;usare solo return T == null;.
md2perpe,

1

Ogni volta che si creano oggetti di classe, è necessario verificare se l'oggetto è nullo o meno utilizzando il codice seguente.

Esempio: oggetto1 è oggetto di classe

void myFunction(object1)
{
  if(object1!=null)
  {
     object1.value1 //If we miss the null check then here we get the Null Reference exception
  }
}

0

Ho appena seguito un metodo che di solito seguiremmo nello script java. Per convertire l'oggetto in stringa e quindi verificare se sono nulli.

var obj = new Object();
var objStr = obj.ToString();
if (!string.IsNullOrEmpty(objStr)){
  // code as per your needs
}

0

Ho fatto più semplice (in modo positivo) e sembra funzionare bene.

Poiché ogni tipo di "oggetto" è almeno un oggetto


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
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.