Mengapa seseorang sering melihat "null! = Variable" daripada "variable! = Null" di C #?

103

Di c #, apakah ada perbedaan dalam kecepatan eksekusi untuk urutan yang Anda nyatakan kondisinya?

if (null != variable) ...
if (variable != null) ...

Sejak baru-baru ini, saya cukup sering melihat yang pertama, dan itu menarik perhatian saya karena saya terbiasa dengan yang kedua.

Jika tidak ada perbedaan, apa keuntungan dari yang pertama?

mr_georg
sumber
Beberapa bahasa pemrograman mendukung untuk menginisialisasi nilai dalam kondisi if. Dalam bahasa seperti itu jika kita ingin membandingkan LValue dengan RValue, sebaiknya gunakan literal ke sisi kiri seperti if (1 == i). jadi secara tidak sengaja jika kita meletakkan = lebih == maka itu memberikan kesalahan kompiler.
Jugal Panchal

Jawaban:

160

Ini adalah penahanan dari C. Dalam C, jika Anda menggunakan kompilator yang buruk atau tidak memiliki peringatan yang cukup tinggi, ini akan dikompilasi tanpa peringatan apa pun (dan memang kode legal):

// Probably wrong
if (x = 5)

padahal yang mungkin Anda maksud

if (x == 5)

Anda dapat mengatasinya di C dengan melakukan:

if (5 == x)

Salah ketik di sini akan menghasilkan kode yang tidak valid.

Sekarang, di C # ini semua piffle. Kecuali jika Anda membandingkan dua nilai Boolean (yang jarang, IME), Anda dapat menulis kode yang lebih mudah dibaca, karena pernyataan "jika" memerlukan ekspresi Boolean untuk memulai, dan jenis " x=5" adalah Int32, bukan Boolean.

Saya menyarankan jika Anda melihat ini dalam kode kolega Anda, Anda mendidik mereka dalam cara-cara bahasa modern, dan menyarankan mereka menulis bentuk yang lebih alami di masa depan.

Jon Skeet
sumber
6
Rekan-rekan saya semua membuat saya gila dengan ini, dan menginginkan tanda kurung kurawal bahkan untuk satu pernyataan setelah jika ... (jika Anda menambahkan sesuatu nanti 'tanpa disadari'). Putar di F # dan Boo (dan YAML), jika bahasa Anda tidak dapat dibaca tanpa indentasi, jadikan itu bagian dari bahasa, kataku.
Benjol
48
Menambahkan kawat gigi itu wajar, IMO - C # tentu tidak berusaha menghentikannya menjadi masalah. Itu sangat berbeda dengan masalah "konstanta == variabel".
Jon Skeet
6
a if (this! = that) {performAsSuch (); } sebenarnya cukup sehat. Argumen "tambahan kemudian"
terasa
3
@jpinto: Saya tidak benar-benar yakin apa yang Anda coba untuk mengatakan di sini - yang Anda lakukan seperti kawat gigi sekitar pernyataan tunggal, atau bahwa Anda tidak? Perbedaan antara ini dan bisnis variabel dalam pertanyaan adalah bahwa dalam C # kode dengan kesalahan ketik adalah kode yang tidak valid sehingga kompilator akan menghentikannya. Hal yang sama tidak berlaku untuk tidak memasang kawat gigi.
Jon Skeet
3
@Benjol Jangan lupa untuk selalu menyediakan else { }klausa kosong jika seseorang perlu menambahkan sesuatu di sana nanti dan lupa menulis elsekata kuncinya sendiri. (Joke)
Jeppe Stig Nielsen
12

Ada alasan bagus untuk menggunakan null dulu: if(null == myDuck)

Jika Anda class Duckmenimpa ==operator, maka if(myDuck == null)bisa masuk ke loop tak terbatas.

Menggunakan nullpertama menggunakan pembanding kesetaraan default dan benar-benar melakukan apa yang Anda inginkan.

(Saya mendengar Anda terbiasa membaca kode yang ditulis seperti itu pada akhirnya - saya hanya belum mengalami transformasi itu).

Berikut ini contohnya:

public class myDuck
{
    public int quacks;
    static override bool operator ==(myDuck a, myDuck b)
    {
        // these will overflow the stack - because the a==null reenters this function from the top again
        if (a == null && b == null)
            return true;
        if (a == null || b == null)
            return false;

        // these wont loop
        if (null == a && null == b)
            return true;
        if (null == a || null == b)
            return false;
        return a.quacks == b.quacks; // this goes to the integer comparison
    }
}
DanW
sumber
11
Ini salah. Suara negatif. Cukup arahkan mouse ke ==operator dan letakkan di sana, dan Anda akan melihat bahwa kelebihan beban yang ditentukan pengguna digunakan dalam kedua kasus. Tentu saja ini dapat membuat perbedaan yang halus jika Anda memeriksa asebelumnya bdan kemudian menukar posisi dari aoperan kanan ke operan kiri. Tapi Anda juga bisa memeriksa bsebelumnya a, dan kemudian b == nullakan menjadi urutan yang dibalik. Ini semua membingungkan jika operator memanggil dirinya sendiri. Sebaliknya, gunakan salah satu operan (atau keduanya) objectuntuk mendapatkan kelebihan beban yang diinginkan. Suka if ((object)a == null)atau if (a == (object)null).
Jeppe Stig Nielsen
10

Seperti semua orang yang telah mencatatnya, ini kurang lebih berasal dari bahasa C di mana Anda bisa mendapatkan kode palsu jika Anda secara tidak sengaja lupa tanda sama dengan kedua. Tetapi ada alasan lain yang juga cocok dengan C #: Keterbacaan.

Ambil saja contoh sederhana ini:

if(someVariableThatShouldBeChecked != null
   && anotherOne != null
   && justAnotherCheckThatIsNeededForTestingNullity != null
   && allTheseChecksAreReallyBoring != null
   && thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded != null)
{
    // ToDo: Everything is checked, do something...
}

Jika Anda hanya ingin menukar semua kata nol ke awal, Anda dapat lebih mudah melihat semua pemeriksaan:

if(null != someVariableThatShouldBeChecked
   && null != anotherOne
   && null != justAnotherCheckThatIsNeededForTestingNullity
   && null != allTheseChecksAreReallyBoring
   && null != thereSeemsToBeADesignFlawIfSoManyChecksAreNeeded)
{
    // ToDo: Everything is checked, do something...
}

Jadi contoh ini mungkin contoh yang buruk (lihat pedoman pengkodean) tetapi pikirkan tentang Anda dengan cepat menggulir file kode lengkap. Dengan hanya melihat polanya

if(null ...

Anda segera tahu apa yang akan terjadi selanjutnya.

Jika sebaliknya, Anda harus selalu memindai hingga akhir baris untuk melihat pemeriksaan nullity, hanya membiarkan Anda tersandung sesaat untuk mengetahui jenis pemeriksaan yang dilakukan di sana. Jadi mungkin penyorotan sintaks dapat membantu Anda, tetapi Anda selalu lebih lambat ketika kata kunci tersebut berada di akhir baris, bukan di depan.

Oliver
sumber
9

Saya kira ini adalah programmer C yang telah mengganti bahasa.

Di C, Anda dapat menulis yang berikut ini:

int i = 0;
if (i = 1)
{
    ...
}

Perhatikan penggunaan satu tanda sama dengan di sana, yang berarti kode akan menetapkan 1 ke variabel i, lalu mengembalikan 1 (tugas adalah ekspresi), dan gunakan 1 dalam pernyataan-if, yang akan ditangani sebagai benar. Dengan kata lain, di atas adalah bug.

Namun dalam C #, ini tidak mungkin. Memang tidak ada perbedaan diantara keduanya.

Lasse V. Karlsen
sumber
1
"Namun dalam C #, ini tidak mungkin" tanpa kompilator mengeluh, karena pernyataan if memerlukan ekspresi boolean, dan yang disediakan adalah tipe int.
Robert Harvey
4

Di masa lalu, orang akan melupakan '!' (atau tambahan '=' untuk kesetaraan, yang lebih sulit dikenali) dan lakukan tugas alih-alih perbandingan. menempatkan null di depan menghilangkan kemungkinan bug, karena null bukanlah nilai-l (IE tidak dapat ditugaskan).

Kebanyakan kompiler modern memberikan peringatan saat Anda melakukan tugas dalam kondisi saat ini, dan C # sebenarnya memberikan kesalahan. Kebanyakan orang tetap menggunakan skema var == null karena lebih mudah dibaca oleh sebagian orang.

Rik
sumber
Semua kompiler C # (perhatikan ini adalah pertanyaan C #) harus gagal untuk mengkompilasi pernyataan "jika" di mana ekspresi bukan Boolean ...
Jon Skeet
4

Saya tidak melihat keuntungan dalam mengikuti konvensi ini. Di C, di mana tipe boolean tidak ada, akan berguna untuk menulis

if( 5 == variable)

daripada

if (variable == 5)

karena jika Anda lupa salah satu tanda eaqual, Anda berakhir dengan

if (variable = 5)

yang memberikan 5 ke variabel dan selalu bernilai true. Tapi di Java, boolean adalah boolean. Dan dengan! =, Tidak ada alasan sama sekali.

Namun, satu nasihat yang bagus adalah menulis

if (CONSTANT.equals(myString))

daripada

if (myString.equals(CONSTANT))

karena membantu menghindari NullPointerExceptions.

Saran saya adalah meminta pembenaran aturan tersebut. Jika tidak ada, mengapa mengikutinya? Itu tidak membantu keterbacaan

Gokkula Sudan R
sumber
0

Bagi saya, gaya yang Anda sukai selalu seperti itu

@Shy - Kemudian lagi jika Anda membingungkan operator maka Anda harus ingin mendapatkan kesalahan kompilasi atau Anda akan menjalankan kode dengan bug - bug yang kembali dan menggigit Anda nanti karena menghasilkan perilaku yang tidak terduga

TheCodeJunkie
sumber
Saya tidak berpikir saya pernah mendengar ada orang yang lebih memilih "konstan == variabel" bentuk lain untuk alasan keamanan, yang sudah ditangani di C #.
Jon Skeet
Saya sendiri lebih suka "variabel == konstan", tetapi saya telah melihat programmer mengadopsi kebalikannya karena mereka merasa itu dibaca lebih alami bagi mereka.
TheCodeJunkie
1
Apakah mereka semua adalah orang dengan masa cuci otak C selama bertahun-tahun, atau apakah itu pilihan yang tulus?
Jon Skeet
0

Seperti yang ditunjukkan banyak orang, sebagian besar dalam kode C lama itu digunakan untuk mengidentifikasi kesalahan kompilasi, karena kompiler menerimanya sebagai legal.

Bahasa pemrograman baru seperti java, go cukup pintar untuk menangkap kesalahan kompilasi seperti itu

Seseorang tidak boleh menggunakan "null! = Variable" seperti kondisi dalam kode karena sangat tidak terbaca

Anand Shah
sumber
-4

Satu hal lagi ... Jika Anda membandingkan variabel dengan konstanta (bilangan bulat atau string untuk ex.), Meletakkan konstanta di sebelah kiri adalah praktik yang baik karena Anda tidak akan pernah mengalami NullPointerExceptions:

int i;
if(i==1){        // Exception raised: i is not initialized. (C/C++)
  doThis();
}

sedangkan

int i;
if(1==i){        // OK, but the condition is not met.
  doThis();
}

Sekarang, karena secara default C # instanciates semua variabel, Anda seharusnya tidak memiliki masalah itu dalam bahasa itu.

karlipoppins
sumber
1
Saya tidak yakin kompiler apa yang Anda gunakan untuk bit pertama kode, tetapi harus dikompilasi (umumnya dengan peringatan). Nilai i tidak ditentukan, tetapi memiliki nilai BEBERAPA.
Dolphin
Tentu saja kedua kode akan dikompilasi! Itulah masalahnya. Coba jalankan kode pertama dan Anda akan mengerti apa yang saya maksud dengan "Pengecualian dinaikkan" ...
karlipoppins
juga tidak mendapatkan perbedaan antara keduanya. Bisakah Anda menjelaskan?
mfazekas
Tidak ada pengecualian kecuali jika Anda mendeklarasikan int * i di C / C ++, dan bahkan dalam kasus itu akan membandingkan pointer dan tidak mengeluarkan pengecualian apa pun ... Seperti Dolphin menyatakan nilainya tidak ditentukan tetapi tidak akan menghasilkan Pengecualian apa pun.
Cobusve
tidak ada pengecualian, katakanlah iadalah nilai acak tanpa inisialisasi yang tepat. ekspresi tersebut memiliki semantik yang sepenuhnya sama di c / c ++
Raffaello