C # 'da neden "değişken! = Boş" yerine "null! = Değişken" görülüyor?


103

C # 'da koşulu belirttiğiniz sıra için yürütme hızında herhangi bir fark var mı?

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

Yakın zamandan beri, ilkini oldukça sık gördüm ve ikinciye alıştığım için dikkatimi çekti.

Fark yoksa birincinin avantajı nedir?



Bazı programlama dilleri, if koşulundaki değeri başlatmayı destekler. Bu tür dillerde LValue ile RValue'yu karşılaştırmak istiyorsak, if (1 == i) gibi değişmezi sol tarafa kullanmak iyi bir uygulamadır. yani yanlışlıkla = yerine == koyarsak derleyici hatası verir.
Jugal Panchal

Yanıtlar:


161

C'den gelen bir engeldir. C'de, ya kötü bir derleyici kullanıyorsanız ya da yeterince yüksek uyarılar almadıysanız, bu hiçbir uyarı olmadan derlenecektir (ve aslında yasal koddur):

// Probably wrong
if (x = 5)

aslında muhtemelen demek istediğin zaman

if (x == 5)

Bunu C'de yaparak aşabilirsiniz:

if (5 == x)

Buradaki bir yazım hatası geçersiz koda neden olur.

Şimdi, C # 'da tüm bunlar saçmalık. Eğer (nadir olan IME) Hesap özeti ile başlamak için Boole ifadesini ve "tipi gerektirmektedir "eğer" bir şekilde, daha okunabilir kod yazabilirsiniz iki Boole değerleri karşılaştırarak sürece x=5" dir Int32, değilBoolean .

Bunu meslektaşlarınızın kodunda görürseniz, onları modern dillerin yollarında eğitmenizi ve gelecekte daha doğal formu yazmalarını önermenizi öneririm.


6
Meslektaşlarımın hepsi bu konuda beni deli ediyor ve if ... ifadesinden sonra tek bir ifade için bile küme parantezleri istiyorlar (daha sonra 'farkında olmadan' bir şey eklemeniz durumunda). F # ve Boo (ve YAML) üzerine yuvarlayın, eğer diliniz girinti olmadan okunamıyorsa, onu dilin bir parçası yapın diyorum.
Benjol

48
Parantez ekleme olduğu IMO, makul - C # kesinlikle bir sorun olmaktan durdurmak için herhangi bir girişimde bulunmaz. Bu, "sabit == değişken" sorunundan çok farklı.
Jon Skeet

6
bir eğer (bu! = o) {performAsSuch (); } aslında oldukça sağlıklı. "Daha sonra ekleme" argümanı bana, eğer (a = 5) yazım hatalarını önlemek / tespit etmemek kadar kırılgan görünüyor
jpinto3912

3
@jpinto: Burada ne söylemeye çalıştığından tam olarak emin değilim - tek ifadelerin etrafında parantezlerden hoşlanıyor musun yoksa sevmiyor musun? Bu ve sorudaki değişken iş arasındaki fark, C # 'da yazım hatası olan kodun geçersiz kod olması, dolayısıyla derleyicinin onu durdurmasıdır. Aynı değil de parantez koyarak için geçerlidir.
Jon Skeet

3
@Benjol else { }Birinin daha sonra bir şey eklemesi gerektiğinde ve elseanahtar kelimeyi kendisinin yazmayı unutması durumunda her zaman boş bir cümle sağlamayı unutmayın . (Şaka)
Jeppe Stig Nielsen

11

Önce null kullanmak için iyi bir neden var: if(null == myDuck)

Sizin ise class Duckgeçersiz kılar ==operatörü sonra if(myDuck == null)sonsuz bir döngüye geçebiliriz.

İlkini kullanmak nullvarsayılan bir eşitlik karşılaştırıcısı kullanır ve aslında niyet ettiğiniz şeyi yapar.

(Sonunda bu şekilde yazılmış kodları okumaya alıştığınızı duydum - sadece bu dönüşümü henüz yaşamadım).

İşte bir örnek:

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

11
Bu yanlış. Olumsuz oy verildi. Sadece fareyi ==operatörün üzerine getirin ve orada bekletin, her iki durumda da kullanıcı tanımlı aşırı yükün kullanıldığını göreceksiniz. Elbette, aönce kontrol bedip sonra konumunu asağ işlenenden sol işlenene değiştirirseniz ince bir fark yaratabilir . Ama daha bönce de kontrol edebilirdiniz ave sonra b == nullsırayı tersine çeviren kişi olurdunuz. Operatörün kendisini aramasını sağlamak kafa karıştırıcı. Bunun yerine, objectistenen aşırı yüklemeyi elde etmek için işlenenlerden birini (veya her ikisini) çevirin. Gibi if ((object)a == null)veya if (a == (object)null).
Jeppe Stig Nielsen

10

Herkesin daha önce belirttiği gibi, ikinci eşittir işaretini yanlışlıkla unutursanız yanlış kod alabileceğiniz aşağı yukarı C dilinden geliyor. Ancak C # ile eşleşen başka bir neden daha var: Okunabilirlik.

Sadece şu basit örneği ele alalım:

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

Tüm boş kelimeleri başa değiştirirseniz, tüm kontrolleri çok daha kolay tespit edebilirsiniz:

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

Bu örnek kötü bir örnek olabilir (kodlama yönergelerine bakın), ancak tam bir kod dosyası üzerinde hızlıca kaydırdığınızı düşünün. Sadece kalıbı görerek

if(null ...

Sırada ne olacağını hemen anlarsınız.

Tam tersi olacaksa, sıfırlık kontrolünü görmek için her zaman satırın sonuna kadar taramanız gerekir, sadece orada ne tür bir kontrol yapıldığını bulmak için bir saniye yanılmanıza izin verin. Söz dizimi vurgulamak size yardımcı olabilir, ancak bu anahtar kelimeler ön yerine satırın sonunda olduğunda her zaman daha yavaşsınızdır.


9

Sanırım bu, dilleri değiştiren bir C programcısı.

C'de şunları yazabilirsiniz:

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

Burada tek bir eşittir işaretinin kullanıldığına dikkat edin; bu, kodun i değişkenine 1 atayacağı, ardından 1 döndüreceği (atama bir ifadedir) ve if-ifadesinde 1 kullanacağı anlamına gelir, bu doğru olarak ele alınacaktır. Başka bir deyişle, yukarıdakiler bir hatadır.

Ancak C # 'da bu mümkün değildir. Aslında ikisi arasında hiçbir fark yok.


1
Derleyici şikayet etmeden "C # 'da bu mümkün değildir" çünkü if ifadesi boolean bir ifade gerektirir ve sağlanan da int türündedir.
Robert Harvey

4

Eskiden insanlar '!' (veya eşitlik için fazladan '=', ki bu daha zor fark edilir) ve karşılaştırma yerine bir ödev yapın. null değerini öne koymak, hata olasılığını ortadan kaldırır, çünkü null bir l-değeri değildir (IE, atanamaz).

Çoğu modern derleyici, bugünlerde bir koşullu olarak bir atama yaptığınızda bir uyarı verir ve C # aslında bir hata verir. Çoğu insan var == null şemasına sadık kalır çünkü bazı insanlar için okuması daha kolaydır.


Tüm C # derleyicileri (bunun bir C # sorusu olduğuna dikkat edin), ifadenin Boolean olmadığı durumda bir "eğer" ifadesi derlemede başarısız olmalıdır ...
Jon Skeet

4

Bu kongreye uymanın bir avantajı görmüyorum. C de, boolean türlerinin bulunmadığı yerlerde, yazmak yararlıdır

if( 5 == variable)

ziyade

if (variable == 5)

çünkü eaqual işaretlerinden birini unutursanız,

if (variable = 5)

değişkene 5 atar ve her zaman doğru olarak değerlendirilir. Ancak Java'da boole, boole'tir. Ve! = İle hiçbir neden yok.

Yine de iyi bir tavsiye yazmaktır

if (CONSTANT.equals(myString))

ziyade

if (myString.equals(CONSTANT))

çünkü NullPointerExceptions'dan kaçınmaya yardımcı olur.

Benim tavsiyem, kuralın gerekçelendirilmesini istemek olacaktır. Hiçbiri yoksa, neden takip etsin? Okunabilirliğe yardımcı olmuyor


0

Bana göre her zaman hangi stili tercih ettiğin oldu

@Shy - Operatörlerin kafasını karıştırırsanız, o zaman bir derleme hatası almak istemelisiniz veya bir hata ile kod çalıştıracaksınız - beklenmedik davranışlar ürettiği için daha sonra geri gelen ve sizi yolda ısıran bir hata


C # 'da ele alınan güvenlik nedenlerinden başka "sabit == değişken" biçimini tercih eden birini hiç duymadığımı sanmıyorum .
Jon Skeet

Ben kendim "değişken == sabit" i tercih ederim, ancak programcıların tersini benimsediğini gördüm çünkü onlar için daha doğal okuduğunu düşünüyorlar.
TheCodeJunkie

1
Arkasında yıllarca C beyin yıkama yapan insanlar mıydı yoksa bu gerçek bir seçim miydi?
Jon Skeet

0

Birçoğunun belirttiği gibi, çoğunlukla eski C kodunda, derleyici bunu yasal olarak kabul ettiği için derleme hatasını tanımlamak için kullanıldı.

Java gibi yeni programlama dili, go bu tür derleme hatalarını yakalayacak kadar akıllıdır

Okunamaz olduğu için kodda "null! = Değişken" gibi koşullar kullanılmamalıdır


-4

Bir şey daha ... Bir değişkeni bir sabitle karşılaştırıyorsanız (örn. Tamsayı veya dize), sabiti sola koymak iyi bir uygulamadır çünkü asla NullPointerExceptions ile karşılaşmayacaksınız:

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

buna karşılık

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

Şimdi, varsayılan olarak C # tüm değişkenleri temsil ettiğinden, o dilde bu sorunu yaşamamalısınız.


1
İlk kod biti için hangi derleyiciyi kullandığınızdan emin değilim, ancak derlemesi gerekir (genellikle bir uyarı ile). İ'nin değeri tanımsız, ancak BAZI değerine sahip.
Dolphin

Elbette her iki kod da derlenecek! İşte sorun da bu. İlk kodu çalıştırmayı deneyin ve "İstisna ortaya çıktı" ile ne demek istediğimi anlayacaksınız ...
koni

ayrıca ikisi arasındaki farkı anlamamaktır. Açıklayabilir misin?
mfazekas

C / C ++ 'da int * i bildirmediğiniz sürece bir istisna yok ve bu durumda bile işaretçileri karşılaştıracak ve herhangi bir istisna atmayacak ... Dolphin'in belirttiği gibi, değerin tanımsız olduğunu ancak herhangi bir İstisna oluşturmayacağını belirtti.
Cobusve

istisna yok, diyelim ki iuygun bir başlatma olmadan rastgele bir değer. ifade c / c ++ 'da tamamen aynı anlamsallığa sahip
Raffaello
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.