Memeriksa apakah suatu objek nol dalam C #

226

Saya ingin mencegah pemrosesan lebih lanjut pada objek jika itu nol.

Dalam kode berikut ini saya memeriksa apakah objek tersebut null oleh:

if (!data.Equals(null))

dan

if (data != null)

Namun, saya menerima NullReferenceExceptiondi dataList.Add(data). Jika objek itu nol, seharusnya tidak pernah masukif pernyataan!

Jadi, saya bertanya apakah ini cara yang tepat untuk memeriksa apakah suatu objek adalah nol:

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

Jika ini adalah cara yang tepat untuk memeriksa apakah objek tersebut null, apa yang saya lakukan salah (bagaimana saya bisa mencegah pemrosesan lebih lanjut pada objek untuk menghindari NullReferenceException)?

pengembang
sumber
13
Anda juga harus menggunakan throw e;versusthrow new Exception(e.ToString());
Nix
17
di C # Anda harus selalu menggunakan != nullcek nol Anda. .Equalsakan selalu melempar eksepsi jika objeknya nol.
Kyle Trauberman
42
@Nix: throw e;tidak jauh lebih baik. throw;, di sisi lain ...
Jon
4
@developer: e.ToString()akan menghasilkan string yang tidak hanya mencakup pesan kesalahan, tetapi juga semua InnerExceptionsdan jejak stack. Jadi itu semacam pesan pengecualian yang sangat berat. Jika Anda (benar!) Ingin menyimpan informasi ini, dan tetap di tempatnya, gunakan saja throw;.
Jon
14
Coba / tangkap tidak melakukan apa-apa saat ini. Semua orang mengatakan gunakan saja "lempar" tetapi jika Anda tidak melakukan apa-apa dengan pengecualian tetapi melempar kembali, mengapa harus mencoba / menangkap blok sama sekali? Biasanya Anda menangkap pengecualian untuk menanganinya dengan anggun, membersihkan sumber daya (lebih baik dengan klausa "akhirnya") atau melakukan semacam penebangan sebelum melemparkan kembali pengecualian. Tidak ada yang terjadi dalam kode ini, jadi tidak perlu mencoba / menangkap sama sekali.
David Peterson

Jawaban:

252

Bukan dataitu null, tapi dataList.

Anda harus membuatnya dengan

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

Bahkan lebih baik: karena ini adalah ladang, buatlah itu private. Dan jika tidak ada yang menghalangi Anda, lakukan juga readonly. Latihan yang bagus.

Ke samping

Cara yang benar untuk memeriksa nullity adalah if(data != null). Cek semacam ini ada di mana-mana untuk jenis referensi; bahkan Nullable<T>mengesampingkan operator kesetaraan menjadi cara yang lebih nyaman untuk mengekspresikan nullable.HasValueketika memeriksa nullity.

Jika Anda melakukannya if(!data.Equals(null))maka Anda akan mendapatkan NullReferenceExceptionif data == null. Yang agak lucu karena menghindari pengecualian ini adalah tujuan di tempat pertama.

Anda juga melakukan ini:

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

Ini jelas tidak baik. Saya bisa membayangkan bahwa Anda meletakkannya di sana supaya Anda bisa masuk ke debugger saat masih di dalam metode, dalam hal ini abaikan paragraf ini. Kalau tidak, jangan menangkap pengecualian untuk apa pun. Dan jika Anda melakukannya, rethrow mereka hanya menggunakan throw;.

Jon
sumber
5
Saya telah melihat juga Object.ReferenceEquals (obj, null) untuk tujuan ini. Apakah itu untuk menghindari pengesampingan kesetaraan?
Luca
2
@LucaPiccioni Saya sudah menggunakannya untuk mencegah nilai-jenis-mengeluh ketika menggunakan obat generik: geekality.net/2009/11/13/generics-and-checking-for-null
Svish
4
Saya lebih suka null != data. Menempatkan konstanta pertama-tama mengubah kesalahan ketik bonehead null = datamenjadi kesalahan kompiler, bukan tugas yang tidak disengaja. (Juga berfungsi untuk ==.)
jpmc26
6
@ jpmc26: Di C # if (data = null)sudah ada kesalahan waktu kompilasi, jadi walaupun butuh beberapa dekade untuk sampai di sana, kita tidak perlu benar-benar waspada lagi. Bahkan kompiler C ++ akan dengan mudah menghasilkan peringatan tentang kemungkinan tugas yang tidak diinginkan untuk kode itu.
Jon
Luca, Anda juga dapat menghindari override kesetaraan dengan melemparkan ke 'objek' dalam tes. Pada nada yang sama, jawaban ini seharusnya mengklaim ini sebagai gantinya: "jika ((objek) data! = Null)" karena itu menghindari kesalahan ketika kesetaraan telah ditimpa.
DAG
81

dalam penggunaan C #> 7.0

if (obj is null) ...

Ini akan mengabaikan == atau! = Yang ditentukan oleh objek (kecuali tentu saja Anda ingin menggunakannya ...)

Untuk tidak menggunakan nol if (obj is object)(atau if (!(obj is null)))

kofifus
sumber
1
Saya ingin tahu apakah ada "bukan nol"? (Python akan mengatakan obj is not null)
sehe
1
Mengapa itu lebih baik daripada jika (obj! = Null) yang lebih mudah dibaca
Orn Kristjansson
38
Berharap mereka menerapkan if (obj aint null):(
Nick Bull
10
Karena tidak ada nol adaif (obj is object)
yatskovsky
3
@OrnKristjansson karena! = Dan == dapat diganti.
mitchellJ
61

C # 6 memiliki pemeriksaan null monadik :)

sebelum:

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

setelah:

var bestValue = points?.FirstOrDefault()?.X ?? -1;
Jowen
sumber
7
Karena "komentar hanya dapat diedit selama 5 menit"? Apa? Bagaimanapun ... Ketika saya mulai melakukannya .. Saya datang ke sini untuk mencari sintaks yang lebih baik untuk diungkapkan result = myObject == null ? null : myObject.SomePropertydan contoh Anda memberi saya tip untuk menulis result = myObject?.SomeProperty. Pria!! Itu licik. Saya masih suka coding ...
Adam Cox
27

DataList Anda adalah nol karena belum dibuat, dilihat dari kode yang telah Anda posting.

Mencoba:

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
sumber
3
Selain itu, hanya untuk menambahkan, jika data nol, tidak akan macet, Anda dapat menambahkan nol ke Daftar <Object>.
DaveShaw
7
Tetapi mencoba melakukan. Sama dengan nol akan melempar pengecualian. Harus dilakukan! = Null
glosrob
@glosrob: Ah !! Apa kekhilafan! Saya berpikir bahwa NullReferenceException berasal dari objek .. bukan daftar! Saya baru mengenal c # dan saya pikir ada cara khusus untuk memeriksa null di c #!
pengembang
Itu juga, tetapi saya melihat Ed S. telah menutupinya.
DaveShaw
1
@ DaveShaw: Terima kasih atas kepala. Saya ingin menghindari objek nol yang ditambahkan untuk diproses nanti, jadi saya masih akan melakukan pemeriksaan. :)
pengembang
19

[Diedit untuk mencerminkan petunjuk oleh @ kelton52]

Cara termudah adalah melakukan object.ReferenceEquals(null, data)

Karena (null==data)TIDAK dijamin bekerja:

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

Menghasilkan:

Membandingkan '' dengan 'Nully'

Benar

Salah

Gatopeich
sumber
1
Sebenarnya saya baru saja mencoba ini, dan pernyataan 'Keuntungan yang tersirat adalah bahwa ia mengabaikan semua pengesampingan yang mungkin ada di kelas data, seperti "operator! =".' Sepertinya tidak berlaku.
Kelly Elton
9

Tidak, Anda harus menggunakan !=. Jika datasebenarnya nol maka program Anda hanya akan crash dengan NullReferenceExceptionsebagai akibat dari mencoba memanggil Equalsmetode null. Sadari juga bahwa, jika Anda secara khusus ingin memeriksa kesetaraan referensi, Anda harus menggunakan Object.ReferenceEqualsmetode ini karena Anda tidak pernah tahu bagaimana Equalspenerapannya.

Program Anda macet karena dataListbatal karena Anda tidak pernah menginisialisasi.

Ed S.
sumber
7

Masalah dalam hal ini bukan itu data nol. Itu dataListsendiri adalah nol.

Di tempat Anda mendeklarasikan dataListAnda harus membuat Listobjek baru dan menetapkannya ke variabel.

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

Selain jawaban @Jose Ortega , lebih baik menggunakan metode ekstensi

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

Dan gunakan IsNullmetode untuk semua objek seperti:

object foo = new object(); //or any object from any class
if (foo.IsNull())
   {
     // blah blah //
   }
Ali
sumber
1
Kenapa return T == null ? true : false;dan tidak adil return T == null;?
md2perpe
1
Saya tidak yakin saya setuju. Tampaknya aneh memanggil metode pada objek untuk memeriksa apakah itu nol. Tanpa tahu itu adalah metode ekstensi Anda akan berpikir itu akan melempar pengecualian referensi nol.
Jamie Twells
Benar-benar dapat mengkonfirmasi bahwa Jamie benar - ini tidak akan berhasil. Saya tahu karena saya memiliki momen kelinci dan menulis metode ekstensi yang sama: P Kode selalu melemparkan pengecualian referensi nol, itu sama sekali tidak akan masuk ke metode ekstensi.
James King
Sebenarnya saya ingin mengatakan Anda dapat melakukan itu dengan metode ekstensi ... mungkin kode memiliki beberapa masalah dan dapat ditingkatkan!
Ali
Anda dapat memanggil metode ekstensi pada objek nol; Anda hanya perlu membandingkan T (dalam hal ini) dengan nol untuk berhati-hati. Tapi Jamie benar, itu terlihat aneh.
Tim Barrass
3

Pada C # 8 Anda dapat menggunakan pola properti 'kosong' (dengan pencocokan pola ) untuk memastikan objek tidak nol:

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

Pendekatan ini berarti " jika objek referensi instance dari sesuatu " (yaitu itu bukan nol).

Anda dapat menganggap ini sebagai kebalikan dari: if (obj is null)... . yang akan mengembalikan true ketika objek tidak merujuk instance dari sesuatu.

Untuk info lebih lanjut tentang pola dalam C # 8.0 baca di sini .

Darren Ruane
sumber
3

Pada C # 9 yang dapat Anda lakukan

if (obj is null) { ... }

Untuk tidak menggunakan nol

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

Jika Anda perlu menimpa penggunaan perilaku ini ==dan !=sesuai.

Eugene Chybisov
sumber
2

Jeffrey L Whitledge benar. Obyek `dataList´ Anda sendiri adalah nol.

Ada juga masalah lain dengan kode Anda: Anda menggunakan kata kunci ref, yang berarti data argumen tidak boleh nol! MSDN mengatakan:

Argumen yang diteruskan ke parameter ref harus diinisialisasi terlebih dahulu. Ini berbeda dari keluar, yang argumennya tidak harus secara eksplisit diinisialisasi sebelum disahkan

Ini juga bukan ide yang baik untuk menggunakan obat generik dengan tipe `Object`. Generik harus menghindari tinju / unboxing dan juga memastikan keamanan jenis. Jika Anda ingin jenis yang umum buat metode Anda menjadi umum. Akhirnya kode Anda akan terlihat seperti ini:

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
sumber
2

Seperti orang lain telah menunjukkan, itu bukan datamelainkan kemungkinan dataListyangnull . Selain itu...

catch- throwAdalah antipattern yang hampir selalu membuat saya ingin muntah setiap kali melihatnya. Bayangkan bahwa ada sesuatu yang salah di dalam sesuatu yang doOtherStuff()memanggil. Yang Anda dapatkan hanyalah sebuah Exceptionbenda, dilemparkan ke throwdalam AddData(). Tidak ada jejak stack, tidak ada informasi panggilan, tidak ada keadaan, tidak ada sama sekali untuk menunjukkan sumber sebenarnya dari masalah, kecuali jika Anda masuk dan beralih debugger Anda untuk istirahat dengan pengecualian dilemparkan daripada pengecualian tidak ditangani. Jika Anda menangkap pengecualian dan hanya melemparkannya kembali dengan cara apa pun , terutama jika kode di blok percobaan sama sekali nontrivial, bantulah diri Anda sendiri (dan kolega Anda, saat ini dan di masa depan) dan buang seluruh try-catch blok . Memang,throw;lebih baik daripada alternatif, tetapi Anda masih memberi diri Anda (atau siapa pun yang mencoba untuk memperbaiki bug dalam kode) benar-benar tidak perlu sakit kepala. Ini bukan untuk mengatakan bahwa coba-tangkap-lempar tentu jahat, asalkan Anda melakukan sesuatu yang relevan dengan objek pengecualian yang dilemparkan ke dalam blok tangkap.

Lalu ada potensi masalah penangkapan Exceptiondi tempat pertama, tapi itu masalah lain, terutama karena dalam kasus khusus ini Anda melempar pengecualian.

Hal lain yang menurut saya lebih dari sedikit berbahaya adalah yang databerpotensi mengubah nilai selama pelaksanaan fungsi, karena Anda melewati referensi. Jadi cek nol mungkin lulus tetapi sebelum kode melakukan sesuatu dengan nilainya, itu berubah - mungkin ke null. Saya tidak yakin apakah ini masalah atau tidak (mungkin tidak), tetapi tampaknya patut diwaspadai.

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

menggunakan:

isnull(object.check.it)

Penggunaan bersyarat:

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

Pembaruan (dengan cara lain) diperbarui pada tanggal 08/31/2017. Terima kasih atas komentarnya.

public static bool isnull(object T)
{
    return T ? true : false;
}
Jose Ortega
sumber
5
cond ? true : false;sepenuhnya sama dengan adil cond. Ini tidak menambah apa pun.
lericson
Maaf, tetapi jika Anda memeriksa fungsinya, ia harus mengembalikan nilai bool. Saya melakukan formalisme. Jadi periksa kembali
Jose Ortega
3
maksudnya return T == null;juga mengembalikan boolean!
MQoder
Aku tahu apa yang dia katakan. ty
Jose Ortega
1
Alih-alih return T == null ? true : false;hanya digunakan return T == null;.
md2perpe
1

Setiap kali Anda membuat objek kelas Anda harus memeriksa apakah objek tersebut null atau tidak menggunakan kode di bawah ini.

Contoh: object1 adalah objek kelas

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

Saya hanya mengikuti metode yang biasanya kita ikuti dalam java script. Untuk mengonversi objek menjadi string, lalu periksa apakah itu nol.

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

Saya melakukan lebih sederhana (cara positif) dan sepertinya bekerja dengan baik.

Karena segala jenis "objek" setidaknya merupakan objek


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