Überprüfen, ob ein Objekt in C # null ist

226

Ich möchte die weitere Verarbeitung eines Objekts verhindern, wenn es null ist.

Im folgenden Code überprüfe ich, ob das Objekt entweder null ist:

if (!data.Equals(null))

und

if (data != null)

Ich erhalte jedoch eine NullReferenceExceptionat dataList.Add(data). Wenn das Objekt null war, hätte es niemals die ifAnweisung eingeben dürfen!

Daher frage ich, ob dies die richtige Methode ist, um zu überprüfen, ob ein Objekt null ist:

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;
}

Wenn dies die richtige Methode ist, um zu überprüfen, ob das Objekt null ist, was mache ich falsch (wie kann ich die weitere Verarbeitung des Objekts verhindern, um die NullReferenceException zu vermeiden)?

Entwickler
quelle
13
Sie sollten auch throw e;versusthrow new Exception(e.ToString());
Nix
17
in C # sollten Sie immer != nullin Ihren Nullprüfungen verwenden. .Equalslöst immer eine Ausnahme aus, wenn das Objekt null ist.
Kyle Trauberman
42
@Nix: throw e;ist nicht viel besser. throw;, auf der anderen Seite ...
Jon
4
@developer: Erzeugt e.ToString()eine Zeichenfolge, die nicht nur die Fehlermeldung, sondern auch die aller InnerExceptionsund die Stapelverfolgung enthält. Das ist also eine sehr fettreiche Ausnahmemeldung. Wenn Sie (zu Recht!) Diese Informationen aufbewahren und dort aufbewahren möchten, wo sie hingehören, verwenden Sie sie einfach throw;.
Jon
14
Der Versuch / Fang macht im Moment nichts. Alle sagen, benutze einfach "werfen", aber wenn du mit der Ausnahme nichts machst, sondern es erneut wirfst, warum überhaupt einen Try / Catch-Block? Normalerweise fangen Sie Ausnahmen ab, um sie ordnungsgemäß zu behandeln, Ressourcen zu bereinigen (besser mit der "finally" -Klausel) oder führen eine Protokollierung durch, bevor Sie die Ausnahme erneut auslösen. Keines davon passiert in diesem Code, so dass überhaupt kein Versuch / Fang erforderlich ist.
David Peterson

Antworten:

252

Es ist nicht datadas ist null, aber dataList.

Sie müssen eine mit erstellen

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

Noch besser: Da es ein Feld ist, mach es private. Und wenn dich nichts daran hindert, mach es auch readonly. Nur gute Übung.

Beiseite

Der richtige Weg, um auf Nichtigkeit zu prüfen, ist if(data != null). Diese Art der Überprüfung ist für Referenztypen allgegenwärtig. Nullable<T>überschreibt sogar den Gleichheitsoperator, um eine bequemere Ausdrucksweise nullable.HasValuebei der Überprüfung auf Nichtigkeit zu bieten.

Wenn Sie dies tun, erhalten if(!data.Equals(null))Sie ein NullReferenceExceptionWenn data == null. Was irgendwie komisch ist, da die Vermeidung dieser Ausnahme in erster Linie das Ziel war.

Sie machen das auch:

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

Das ist definitiv nicht gut. Ich kann mir vorstellen, dass Sie es dort ablegen, damit Sie in den Debugger einbrechen können, während Sie sich noch in der Methode befinden. In diesem Fall ignorieren Sie diesen Absatz. Andernfalls fangen Sie keine Ausnahmen umsonst. Und wenn Sie dies tun, werfen Sie sie mit just neu throw;.

Jon
quelle
5
Ich habe zu diesem Zweck auch Object.ReferenceEquals (obj, null) gesehen . Soll Gleichstellungsüberschreibungen vermieden werden?
Luca
2
@ LucaPiccioni Ich habe es verwendet, um Werttyp-Beschwerden bei der Verwendung von Generika zu verhindern: geekality.net/2009/11/13/generics-and-checking-for-null
Svish
4
Ich bevorzuge null != data. Wenn Sie die Konstante an die erste Stelle setzen, wird der Tippfehler des Boneheads null = dataeher zu einem Compilerfehler als zu einer unbeabsichtigten Zuweisung. (Funktioniert auch für ==.)
jpmc26
6
@ jpmc26: In C # if (data = null)ist bereits ein Fehler bei der Kompilierung aufgetreten. Selbst wenn es Jahrzehnte gedauert hat , müssen wir nicht mehr wirklich darauf achten. Selbst C ++ - Compiler geben leicht eine Warnung vor einer möglichen unbeabsichtigten Zuweisung für diesen Code aus.
Jon
Luca, du kannst Gleichheitsüberschreibungen auch vermeiden, indem du im Test auf 'Objekt' wirfst. In ähnlicher Weise sollte diese Antwort stattdessen Folgendes beanspruchen: "if ((Objekt-) Daten! = Null)", da Fehler vermieden werden, wenn die Gleichheit überschrieben wurde.
DAG
80

in C #> 7.0 verwenden

if (obj is null) ...

Dadurch werden alle vom Objekt definierten == oder! = Ignoriert (es sei denn, Sie möchten sie natürlich verwenden ...).

Für nicht null verwenden if (obj is object)(oder if (!(obj is null)))

Kofifus
quelle
1
Ich frage mich, gibt es ein "ist nicht null"? (Python würde sagen obj is not null)
sehe
1
Warum ist das besser als wenn (obj! = Null), was besser lesbar ist
Orn Kristjansson
38
Ich wünschte, sie würden implementieren if (obj aint null):(
Nick Bull
8
Denn es gibt nicht nullif (obj is object)
yatskovsky
3
@OrnKristjansson weil! = Und == überschrieben werden können.
Mitchell
61

C # 6 hat eine monadische Nullprüfung :)

Vor:

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

nach dem:

var bestValue = points?.FirstOrDefault()?.X ?? -1;
Jowen
quelle
7
Weil "Kommentare nur für 5 Minuten bearbeitet werden dürfen"? Was? Wie auch immer ... Als ich dazu kam ... kam ich hierher, um eine bessere Syntax zum Ausdrücken zu finden, result = myObject == null ? null : myObject.SomePropertyund Ihr Beispiel gab mir einen Tipp zum Schreiben result = myObject?.SomeProperty. Mann!! Das ist hinterhältig. Ich liebe es immer noch zu programmieren ...
Adam Cox
27

Ihre Datenliste ist null, da sie nach dem von Ihnen veröffentlichten Code nicht instanziiert wurde.

Versuchen:

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;

}}

Glosrob
quelle
3
Nur um hinzuzufügen, wenn Daten null sind und nicht abstürzen, können Sie einer Liste <Objekt> null hinzufügen.
DaveShaw
7
Der Versuch, .Equals auf einer Null zu machen, würde eine Ausnahme auslösen. Sollte tun! = Null
Glosrob
@glosrob: Ah !! Was für ein Versehen! Ich dachte, dass die NullReferenceException vom Objekt stammt .. nicht von der Liste! Ich bin neu in c # und dachte mir, dass es eine spezielle Möglichkeit gibt, in c # nach Null zu suchen!
Entwickler
Auch das, aber ich sah, dass Ed S. es abgedeckt hatte.
DaveShaw
1
@ DaveShaw: Danke für das Heads Up. Ich möchte jedoch vermeiden, dass ein Nullobjekt für die spätere Verarbeitung hinzugefügt wird, daher werde ich trotzdem eine Überprüfung durchführen. :)
Entwickler
19

[Bearbeitet, um den Hinweis von @ kelton52 wiederzugeben]

Der einfachste Weg ist zu tun object.ReferenceEquals(null, data)

Da (null==data)ist NICHT garantiert zu arbeiten:

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));
}

Produziert:

Vergleich von '' mit 'Nully'

Wahr

Falsch

gatopeich
quelle
1
Eigentlich habe ich es gerade versucht und die Bemerkung "Der implizite Vorteil ist, dass alle Überschreibungen ignoriert werden, die in der Datenklasse vorhanden sein können, wie" operator! = "." Scheint nicht wahr zu sein.
Kelly Elton
9

Nein, du solltest verwenden !=. Wenn datatatsächlich null ist, stürzt Ihr Programm nur mit einem ab, NullReferenceExceptionwenn versucht wird, die EqualsMethode aufzurufen null. Beachten Sie auch, dass Sie die Object.ReferenceEqualsMethode verwenden sollten, wenn Sie speziell auf Referenzgleichheit prüfen möchten, da Sie nie wissen, wie Equalssie implementiert wurde.

Ihr Programm stürzt ab, weil dataListes null ist, da Sie es nie initialisieren.

Ed S.
quelle
7

Das Problem in diesem Fall ist nicht, dass dataes null ist. Es ist so, dass dataListselbst null ist.

An der Stelle, an der Sie deklarieren dataList, sollten Sie ein neues ListObjekt erstellen und es der Variablen zuweisen.

List<object> dataList = new List<object>();
Jeffrey L Whitledge
quelle
5

Zusätzlich zur Antwort von @Jose Ortega ist die Erweiterungsmethode besser geeignet

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

Und verwenden Sie die IsNullMethode für alle Objekte wie:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }
Ali
quelle
1
Warum return T == null ? true : false;und nicht nur return T == null;?
md2perpe
1
Ich bin mir nicht sicher, ob ich damit einverstanden bin. Es sieht seltsam aus, eine Methode für ein Objekt aufzurufen, um zu überprüfen, ob es null ist. Ohne zu wissen, dass es sich um eine Erweiterungsmethode handelt, würde man denken, dass sie eine Nullreferenzausnahme auslösen würde.
Jamie Twells
Kann völlig bestätigen, dass Jamie richtig ist - das wird nicht funktionieren. Ich weiß, weil ich einen Hasenhirn-Moment hatte und eine ähnliche Erweiterungsmethode geschrieben habe: P Der Code hat immer eine Nullreferenzausnahme ausgelöst, er wird absolut nicht in die Erweiterungsmethode eingehen.
James King
Eigentlich möchte ich sagen, dass Sie das mit der Erweiterungsmethode tun können ... möglicherweise hat der Code ein Problem und kann sich verbessern!
Ali
Sie können eine Erweiterungsmethode für ein Nullobjekt aufrufen. Sie müssen nur T (in diesem Fall) mit null vergleichen, um vorsichtig zu sein. Jamie hat recht, aber es sieht seltsam aus.
Tim Barrass
3

Ab C # 8 können Sie das Eigenschaftsmuster 'leer' (mit Mustervergleich ) verwenden, um sicherzustellen, dass ein Objekt nicht null ist:

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

Dieser Ansatz bedeutet " wenn das Objekt auf eine Instanz von etwas verweist " (dh es ist nicht null).

Sie können sich das als das Gegenteil von vorstellen : if (obj is null).... Dies gibt true zurück, wenn das Objekt nicht auf eine Instanz von etwas verweist.

Weitere Informationen zu Mustern in C # 8.0 finden Sie hier .

Darren Ruane
quelle
3

Ab C # 9 können Sie tun

if (obj is null) { ... }

Für nicht null verwenden

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

Wenn Sie dieses Verhalten überschreiben müssen, verwenden Sie ==und !=entsprechend.

Eugene Chybisov
quelle
2

Jeffrey L Whitledge hat recht. Ihr `dataList´-Objekt selbst ist null.

Es gibt noch ein weiteres Problem mit Ihrem Code: Sie verwenden das Schlüsselwort ref, was bedeutet, dass die Argumentdaten nicht null sein dürfen! Die MSDN sagt:

Ein an einen ref-Parameter übergebenes Argument muss zuerst initialisiert werden. Dies unterscheidet sich von out, dessen Argumente nicht explizit initialisiert werden müssen, bevor sie übergeben werden

Es ist auch keine gute Idee, Generika mit dem Typ "Objekt" zu verwenden. Generika sollten das Ein- und Auspacken vermeiden und auch die Typensicherheit gewährleisten. Wenn Sie einen gemeinsamen Typ möchten, machen Sie Ihre Methode generisch. Schließlich sollte Ihr Code so aussehen:

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) {
        //...
      }
    }
DiableNoir
quelle
2

Wie andere haben bereits darauf hingewiesen, ist es nicht , datasondern wahrscheinlich dataListdas ist null. Darüber hinaus...

catch- throwist ein Antimuster, das mich fast immer dazu bringt, mich jedes Mal zu übergeben, wenn ich es sehe. Stellen Sie sich vor, dass etwas in etwas, das doOtherStuff()anruft, schief geht . Alles , was Sie zurück erhalten , ist ein ExceptionObjekt, bei dem geworfen throwin AddData(). Keine Stapelverfolgung, keine Aufrufinformationen, kein Status, überhaupt nichts, was auf die wahre Ursache des Problems hinweist, es sei denn, Sie gehen hinein und schalten Ihren Debugger so, dass eine ausgelöste Ausnahme unterbrochen wird, anstatt eine Ausnahme nicht zu behandeln. Wenn Sie eine Ausnahme abfangen und sie auf irgendeine Weise erneut auslösen , insbesondere wenn der Code im try-Block in irgendeiner Weise nicht trivial ist, tun Sie sich selbst (und Ihren Kollegen, Gegenwart und Zukunft) einen Gefallen und werfen Sie den gesamten try- catchBlock aus . Gewährt,throw;ist besser als die Alternativen, aber Sie geben sich selbst (oder wer auch immer versucht, einen Fehler im Code zu beheben) völlig unnötige Kopfschmerzen. Dies bedeutet nicht, dass Try-Catch-Throw per se notwendigerweise böse ist, solange Sie mit dem Ausnahmeobjekt, das in den Catch-Block geworfen wurde, etwas Relevantes tun .

Dann gibt es die potenziellen Probleme, überhaupt zu fangen Exception, aber das ist eine andere Sache, zumal Sie in diesem speziellen Fall eine Ausnahme auslösen.

Eine andere Sache, die mir mehr als gefährlich erscheint, ist, dass datasich der Wert während der Ausführung der Funktion möglicherweise ändern kann, da Sie als Referenz übergeben werden. Die Nullprüfung wird möglicherweise bestanden, aber bevor der Code etwas mit dem Wert anfangen kann, wird er geändert - vielleicht in null. Ich bin mir nicht sicher, ob dies ein Problem ist oder nicht (es könnte nicht sein), aber es scheint sich zu lohnen, darauf zu achten.

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

verwenden:

isnull(object.check.it)

Bedingte Verwendung:

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

Update (auf andere Weise) aktualisiert am 31.08.2017. Danke für den Kommentar.

public static bool isnull(object T)
{
    return T ? true : false;
}
Jose Ortega
quelle
5
cond ? true : false;ist völlig gleichbedeutend mit nur cond. Dies fügt nichts hinzu.
Lericson
Es tut mir leid, aber wenn Sie die Funktion überprüfen, muss sie einen Bool-Wert zurückgeben. Ich mache den Formalismus. Also überprüfen Sie es noch einmal
Jose Ortega
3
er meint return T == null;auch einen booleschen Wert zurück!
MQoder
Ich weiß, was er sagt. ty
Jose Ortega
1
Anstatt return T == null ? true : false;nur zu benutzen return T == null;.
md2perpe
1

Wenn Sie Objekte der Klasse erstellen, müssen Sie mithilfe des folgenden Codes überprüfen, ob das Objekt null ist oder nicht.

Beispiel: Objekt1 ist Objekt der Klasse

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

Ich habe gerade eine Methode befolgt, die wir normalerweise in Java-Skripten anwenden würden. Um ein Objekt in eine Zeichenfolge zu konvertieren und dann zu überprüfen, ob sie null sind.

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

Ich habe es einfacher gemacht (positiver Weg) und es scheint gut zu funktionieren.

Da jede Art von "Objekt" zumindest ein Objekt ist


    if (MyObj is Object)
    {
            //Do something .... for example:  
            if (MyObj is Button)
                MyObj.Enabled = true;
    }
Gilles5678
quelle