Geçiş ifadesi düşüşü… buna izin verilmeli mi? [kapalı]


120

Hatırlayabildiğim sürece, anahtar deyimi düşüşünü kullanmaktan kaçındım. Aslında, bunun anahtar ifadesindeki bir hatadan başka bir şey olmadığı için başıma delindiği için, bir şeyler yapmanın olası bir yolu olarak bilincime girdiğini hiç hatırlayamıyorum. Ancak bugün, onu tasarım gereği kullanan bir kodla karşılaştım ve bu da beni hemen topluluktaki herkesin switch deyiminin düşmesi hakkında ne düşündüğünü merak etmeye itti.

Bu, bir programlama dilinin açıkça izin vermemesi gereken bir şey mi (bir geçici çözüm sağlasa da C # gibi) ya da programcının eline bırakacak kadar güçlü herhangi bir dilin özelliği mi?

Düzenleme: Düşüş ile ne demek istediğime yeterince spesifik değildim. Bu türü çok kullanıyorum:

    switch(m_loadAnimSubCt){
        case 0:
        case 1:
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

Ancak bunun gibi bir şeyle ilgileniyorum.

   switch(m_loadAnimSubCt){
        case 0:
        case 1:
            // Do something, but fall through to the other cases
            // after doing it.

        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }

Bu şekilde, vaka 0, 1 olduğunda, switch ifadesindeki her şeyi yapacaktır. Bunu tasarım gereği gördüm ve switch ifadelerinin bu şekilde kullanılması konusunda hemfikir olup olmadığımı bilmiyorum. İlk kod örneğinin çok kullanışlı ve güvenli olduğunu düşünüyorum. İkincisi biraz tehlikeli görünüyor.



51
Yapıcı olmadığına katılmıyorum. Soruyla ilgili 27 olumlu oy, başkalarının da bu şekilde düşündüğünü söylüyor.
Wes Modes

2
"yapıcı değil" eski ve biraz belirsiz bir yakın nedendir. Günümüzde, bu tür sorular tamamen fikir temelli olarak kapatılmak üzere işaretlenebilir ve işaretlenmelidir. SO, kod veya tasarımla ilgili yanıtlanabilir sorular içindir, "topluluğun" [her ne ise] Özellik X hakkındaki düşüncem hakkındaki görüşü nedir? 'Değil. Programcılar SE daha uygun olabilirdi, ancak o zaman bile, böylesine geniş ve fikir odaklı bir sorunun değeri hala oldukça şüphelidir.
underscore_d

1
Sonuçların kullanıldığı çok açık kullanım durumları vardır, bu nedenle neden fikir temelli olduğundan emin değilsiniz. Bu sorunun biraz belirsiz olduğuna katılıyorum, ancak yapıcı olmadığı için kapatılmamalıydı. Belki daha net bir durum olarak düzenlenmiştir: "Son durum ne zaman kullanılır?" Net bir cevabı var. İyi C ++ metinleri bunun üzerinden geçer, yeni kodlayıcılar (veya diğer dillerden daha deneyimli kodlayıcılar) için kafa karıştırıcıdır, bu nedenle SO için iyi bir soru gibi görünüyor. Aslında, prototip olarak iyi bir SO sorusu gibi görünüyor . Sorulma şekli mükemmel olmasa bile.
eric

Yanıtlar:


89

Düşüş olarak düşündüğünüz şeye bağlı olabilir. Bu tür şeylerde sorun yok:

switch (value)
{
  case 0:
    result = ZERO_DIGIT;
    break;

  case 1:
  case 3:
  case 5:
  case 7:
  case 9:
     result = ODD_DIGIT;
     break;

  case 2:
  case 4:
  case 6:
  case 8:
     result = EVEN_DIGIT;
     break;
}

Ancak bir kasa etiketiniz ve ardından başka bir kasa etiketine düşen kodunuz varsa, hemen hemen her zaman bu kötülüğü düşünürdüm. Belki de ortak kodu bir işleve taşımak ve her iki yerden çağırmak daha iyi bir fikir olabilir.

Ve lütfen C ++ SSS'nin "kötülük" tanımını kullandığımı unutmayın


Size katılıyorum: Örneğinizi bir sonuç olarak görmüyorum ve eğer birden çok kod bloğu fallthrough yoluyla yürütmek istediğim bir durum varsa, muhtemelen bunu yapmanın daha iyi bir yolu vardır.
Dave DuPlantis

10
+1 sadece "kötülük" tanımı için. Bunu ödünç alacağım, teşekkürler ;-)
Joachim Sauer

Demek istediğini anladım ve haklısın, ama örneğin gerçekten kötü. Hiç kimse böyle basamakları test etmemelidir. Scnr, cevabın zaten doğru.
Tim Büthe

Durumda, C #'ın izin vermediği şey budur. Muhtemelen bir nedenden dolayı :-)
Joey

Ne yazık ki kötülüğün tanımı çevrimdışı oldu
Umarım Yardım

57

İki ucu keskin bir kılıç. Bazen çok yararlıdır, ancak genellikle tehlikelidir.

Ne zaman iyidir? 10 davanın hepsinin aynı şekilde işlenmesini istediğinizde ...

switch (c) {
  case 1:
  case 2:
            ... Do some of the work ...
            /* FALLTHROUGH */
  case 17:
            ... Do something ...
            break;
  case 5:
  case 43:
            ... Do something else ...
            break;
}

Sevdiğim tek kural, molayı hariç tuttuğunuz bir şey yaparsanız, niyetinizin bu olduğunu belirtmek için net bir yoruma / * FALLTHROUGH * / ihtiyacınız olmasıdır.


3
1! Bazen doğru cevap olduğuna katılıyorum ve tasarım gereği yorum yapılması gerektiğine ÇİFT KATILIYORUM. (Bir kod incelemesinde, diğer geliştiricinin, tasarım gereği, boş olmayan bir düşüşün yorumunu YAPTIRIRIM. Olmaz; biz desteklenmeyen bir C # mağazayız :)
John Rudy

4
Ben de uygun olduğu durumlarda kodumda / * FALL THROUGH * / comment kullanıyorum. =]
strager

2
PC-Lint kullanıyorsanız, / * - fallthrough * / eklemeniz gerekir, aksi takdirde şikayet eder.
Steve Melnikoff

1
Yine de, davranışın kasıtlı olduğunu if(condition > 1 && condition <10) {condition = 1}; switch(...açıklığa kavuşturmak isterseniz, davaları da kurtarabilirsiniz (net bakışlar için) ve herkes bu vakaların aynı eylemi tetiklemesini gerçekten istediğinizi görebilir.
Mark

1
Bu hala korkunç bir kodlama. İlk durum bir işlevi çağırmalı, ikinci durum aynı işlevi çağırmalı sonra ikinci bir işlevi çağırmalıdır.
BlueRaja - Dany Pflughoeft

21

Duff'un cihazını duydun mu? Bu, anahtar düşüşü kullanmanın harika bir örneğidir.

Neredeyse tüm dil özellikleri gibi kullanılabilen ve kötüye kullanılabilen bir özelliktir.


Her gün yeni bir şey öğrenin - teşekkürler! Yine de bu tür kıvrımlara rağmen giden zavallı geliştiricileri hissediyorum.
Justin R.

Vay canına, bu beyninizi sarmalayacak bir şey.
Fostah

6
Duff'ın o makalede alıntı yaptığı yorumu not edin: "Bu kod, bu tartışmada bir çeşit argüman oluşturuyor, ancak bunun lehine mi yoksa aleyhine mi emin değilim."
John Carter

Duff'ın cihazı açıkça kötü
Marjeta

21

Düşüş, ne yaptığınıza bağlı olarak gerçekten kullanışlı bir şeydir. Seçenekleri düzenlemenin bu düzgün ve anlaşılır yolunu düşünün:

switch ($someoption) {
  case 'a':
  case 'b':
  case 'c':
    // Do something
    break;

  case 'd':
  case 'e':
    // Do something else
    break;
}

Bunu if / else ile yaptığınızı hayal edin. Bir karmaşa olurdu.


1
Bu tür bir düşüşün çok yararlı olduğunu düşünüyorum
Mitchel Sellers

'bir şey yap' anahtarından biraz daha fazlasıysa if / else yerine karışıklık olur. İf / else ile hangi değişkenin test edildiği her yerde açıktır. Bu küçük örnek bile benim gözümde if / else olsaydı o kadar kötü
görünmezdi

10

Birkaç kez çok faydalı olabilir, ancak genel olarak, istenen davranış hiçbir düşüş değildir. Düşmeye izin verilmelidir, ancak örtük olmamalıdır.

Bazı verilerin eski sürümlerini güncellemek için bir örnek:

switch (version) {
    case 1:
        // Update some stuff
    case 2:
        // Update more stuff
    case 3:
        // Update even more stuff
    case 4:
        // And so on
}

6

Anahtarlardaki geri dönüşler için farklı bir sözdizimi istiyorum, örneğin, errr ..

switch(myParam)
{
  case 0 or 1 or 2:
    // Do something;
    break;
  case 3 or 4:
    // Do something else;
    break;
}

Not: Bu, numaralandırmalarla zaten mümkün olurdu, eğer numaralandırmanızdaki tüm durumları bayrakları kullanarak bildirirseniz, değil mi? O kadar da kötü görünmüyor; vakalar zaten numaranızın bir parçası olabilir (olmalı?).

Belki de bu, uzantı yöntemlerini kullanan akıcı bir arayüz için güzel bir durum (kelime oyunu değildir) olabilir mi? Şey gibi bir şey ...

int value = 10;
value.Switch()
  .Case(() => { /* Do something; */ }, new {0, 1, 2})
  .Case(() => { /* Do something else */ } new {3, 4})
  .Default(() => { /* Do the default case; */ });

Muhtemelen daha az okunabilir olmasına rağmen: P


1
İlk öneriyi çok beğendim. Bu çok iyi okur ve birkaç satır kod kaydeder. İkincisi beynimi sarmak için bir dakika sürdü ama mantıklı, ama bir karmaşa olarak hazırlanmış görünüyor.
Fostah

1
Evet, ben de öyle düşünmüştüm, sadece mevcut dil yapılarını kullanarak geçiş yapmanın farklı bir yolunu bulma çabası içinde ortaya koyduğum rastgele bir zihin osuruğuydu.
Erik van Brakel

Bu soruyu inceledim ve aslında bundan hoşlandım! Bunun okunabilirliğini nasıl artıracağıma dair bir fikrim vardı, ancak SO çok satırlı yorumlar göndermeme izin vermiyor :( Birisi bunu POC gibi uygulamalı, uygulaması ve kullanımı eğlenceli görünüyor (:
Victor Elias

5

Her şeyde olduğu gibi: Dikkatli kullanılırsa zarif bir araç olabilir.

Ancak, ben daha çok dezavantajları haklı düşünüyorum değil kullanmak ve nihayet (C #) artık izin vermeyecek. Sorunlar arasında:

  • bir molayı "unutmak" kolaydır
  • kod geliştiriciler için atlanmış bir molanın kasıtlı olduğu her zaman açık değildir

Anahtar / kasa düşüşünün iyi kullanımı:

switch (x)
{
case 1:
case 2:
case 3:
 Do something
 break;
}

Baaaaad bir anahtar / durum düşüşünün kullanımı:

switch (x)
{
case 1:
    Some code
case 2:
    Some more code
case 3:
    Even more code
    break;
}

Bu, bence hiç kayıpsız if / else yapıları kullanılarak yeniden yazılabilir.

Son sözüm: Bu stilin kullanıldığı ve iyi anlaşıldığı yerlerde eski kodu sürdürmediğiniz sürece , kötü örnekte olduğu gibi düşme durum etiketlerinden uzak durun .


3
Çoğu dil yapısını if () ve goto ... kullanarak yeniden yazabilirsiniz. Bu, açık bir yapıyı terk etmeyi haklı çıkarmaz.
Shog9

2
Biliyorum ama açıkça "durum 1: bazı kod durumu 2: biraz daha fazla kod durumu 3: son kod sonu;" if / else if (benim fikrim) kullanılarak yeniden yazılabilir ve yazılmalıdır.
steffenj

1
Geçişin, bir if-diğers listesinden çok daha hızlı olabileceğini unutmayın. Anahtar bir atlama tablosu kullanır veya bu mümkün olmadığında, koşullu sıçramaları doğrusal bir koşullu atlama listesi yerine bir karar ağacında yapılandırılır. İyi yapılandırılmış iç içe geçmiş If-else ifadeleri en iyi ihtimalle eşit derecede hızlı olacaktır.
Jochem Kuijpers

4

Güçlü ve tehlikelidir. Düşüşle ilgili en büyük sorun, açık olmamasıdır. Örneğin, sık sık düzenlenmiş, arızalı bir anahtarı olan bir kodla karşılaşırsanız, bunun kasıtlı olduğunu ve bir hata olmadığını nasıl anlarsınız?

Kullandığım her yerde, doğru şekilde yorumlanmasını sağlıyorum:

switch($var) {
    case 'first':
        // Fall-through
    case 'second':
        i++;
        break;
 }

2
'İlk' durum için bir kod yoksa amaç açıktır. Orada kod yazarsanız ve ayrıca 'ikinci' durumu için kodu çalıştırmak istiyorsanız, yorum önemlidir. Ama yine de bu senaryodan kaçınırım.
Joel Coehoorn

1
@Joel - Tamamen katılıyorum. Dükkanımda, bu tür durumlarda insanlar kötü yorumlar yaptı ve bence okunabilirliği azaltıyor. Yine de orada kod varsa, son yorum yazın.
Fred Larson

Ne demek "açık değil"? Bu yüzden kırıyoruz; Bunu diğer diller yapar. Bu sadece dillerini sırayla öğrenmemiş insanlar için bir sorun. C #, imho için bir neden olmaksızın varsayılan durum ffs için talep eder.
mckenzm

3

İlk örneğinizdeki gibi düşüşü kullanmak açıkça tamamdır ve bunu gerçek bir hata olarak görmem.

İkinci örnek tehlikelidir ve (kapsamlı bir şekilde yorumlanmadıysa) açık değildir. Öğrencilerimin bu tür yapılar kullanmamayı öğretmek sürece onlar buna değer bu kasıtlı sonbahar-through olduğunu açıklar buna bir açıklama bloğu, ayırmaya çaba düşünün ve neden bu çözüm daha iyi alternatiflerinden daha olduğunu. Bu, özensiz kullanımı caydırır, ancak yine de bir avantaj için kullanıldığı durumlarda buna izin verir.

Bu, uzay projelerinde biri kodlama standardını ihlal etmek istediğinde yaptığımız şeye aşağı yukarı eşdeğer: muafiyet için başvurmak zorunda kaldılar (ve karar hakkında tavsiyede bulunmam istendi).


2

switchİfadelerimin düşmesini sevmiyorum - hataya çok açık ve okunması zor. Tek istisna, birden çok caseifadenin tamamen aynı şeyi yapmasıdır.

Bir switch ifadesinin birden çok dalının kullanmak istediği ortak bir kod varsa, bunu herhangi bir dalda çağrılabilecek ayrı bir ortak işleve çıkarırım.


1

Bazı durumlarda, hatalarını kullanmak programcı açısından bir tembellik eylemidir - bir dizi || ifadeler, ancak bunun yerine bir dizi 'tümünü yakala' anahtar durumu kullanın.

Bununla birlikte, nihayetinde seçeneklere yine de ihtiyacım olacağını bildiğimde (örneğin bir menü yanıtında), ancak tüm seçenekleri henüz uygulamadığımda özellikle yararlı buldum . Aynı şekilde, hem 'a' hem de 'A' için bir düşüş yapıyorsanız, anahtar geçişini kullanmayı bileşik if ifadesinden çok daha temiz buluyorum.

Muhtemelen bir stil meselesi ve programcıların nasıl düşündüğü meselesi, ancak genellikle 'güvenlik' adına bir dilin bileşenlerini kaldırmayı pek sevmiyorum - bu yüzden C'ye ve onun türevlerine / soyundan gelenlere, diyelim ki, Java. Hiçbir "nedenim" olmasa bile, işaretçiler ve benzerleriyle etrafta dolaşabilmeyi seviyorum.


Açıkçası. Switch deyimleri, bir set değeri aracılığıyla bir grup özel kod konumuna atlar. Derleyici muhtemelen bu tür şeyleri yakalarken, bir dizi veya deyim üzerinden bir switch ifadesinin bir hız ve doğruluk değeri vardır. Eğer p 0 veya p 1 veya p 2 ise, kodda p = 2 konumuna atlamak yerine, p'nin 0 ve p'nin 1 olup olmadığını değerlendirmem gerekiyordu. Bu, p0 ve p1 ile aynı oldu. Ama hiç kontrol etmem gerekmedi.
Tatarize

1

Fall-through, yalnızca bir kod bloğuna atlama tablosu olarak kullanıldığında kullanılmalıdır. Kodun herhangi bir kısmı daha fazla vakadan önce koşulsuz bir kesintiye sahipse, tüm vaka grupları bu şekilde bitmelidir.

Başka her şey "kötüdür".

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.