switch deyimi - ulaşılamadığında varsayılan durumu işleme


16

(Sınıfıma ait olan) bir numaradan değerleri işlemek için bir switch deyimi kullanıyorsanız ve her olası değer için bir durum var - "varsayılan" durumda işlemek için kod eklemeye değer mi?

enum MyEnum
{
    MyFoo,
    MyBar,
    MyBat
}

MyEnum myEnum = GetMyEnum();
switch (myEnum)
{
    case MyFoo:
        DoFoo();
        break;
    case MyBar:
        DoBar();
        break;
    case MyBat:
        DoBat();
        break;
    default:
        Log("Unexpected value");
        throw new ArgumentException() 
}

Ben bu kod (hatta birim testleri ile) ulaşılamaz çünkü olduğunu sanmıyorum. İş arkadaşım buna katılmıyor ve bunun MyEnum'a yeni değerlerin eklenmesinden kaynaklanan beklenmedik davranışlara karşı koruduğunu düşünüyor.

Sen ne diyorsun, topluluk?


Diyelim ki MyEnum nullable olmayan bir tür.
sd

3
"Bugün" geçersizdir. Artık kodu korumazken yarın ne olacak? Ya da numaralandırmaya "MyBiz" eklendiğinde ne olur? Caleb'in bakımla ilgili yorumları çok almanca.

1
Tüm durumları kapsamamış bir anahtar varsa, derleyicinize bunun önemli bir hata olduğunu öğretin.

Birisi geçersiz bir değer verir MyEnumve anahtarınızdan geçirirse ne olur ?
Mawg, Monica'nın

1
Hangi dil? Java ise, Enum'un içine bir yöntem koymalı ve sadece switchdeyimi tamamen ortadan kaldırarak (polimorfizm) çağırmalısınız .
user949300

Yanıtlar:


35

Varsayılan durumu dahil etmek, kodunuzun çalışma şeklini değiştirmez, ancak kodunuzu daha sürdürülebilir hale getirir. Kod kırılmasını açık bir şekilde yaparak (bir mesaj kaydedin ve bir istisna atın), şirketinizin önümüzdeki yaz birkaç özellik eklemek için kiraladığı stajyer için büyük bir kırmızı ok eklersiniz. Ok şöyle diyor: "Hey, sen! Evet, seninle konuşuyorum! Numaralamaya başka bir değer katacaksan, buraya da bir dava eklemen iyi olur." Bu ekstra çaba, derlenmiş programa birkaç bayt ekleyebilir, bu da dikkate alınması gereken bir şeydir. Ama aynı zamanda birini (belki de geleceği bile) bir saat ve bir gün verimsiz kafa tırmalama arasında bir yere kurtaracaktır.


Güncelleme: Yukarıda açıklanan durum, yani daha sonraki bir zamanda bir numaralandırmaya eklenen değerlere karşı koruma, derleyici tarafından da yakalanabilir. Numaralandırma türünü açarsanız, ancak numaralandırmadaki olası her değeri kapsayan bir vakanız yoksa Clang (ve gcc, sanırım) varsayılan olarak bir uyarı verir. Örneğin, defaultvakayı anahtarınızdan kaldırır MyBazve numaralandırmaya yeni bir değer eklerseniz , şunları söyleyen bir uyarı alırsınız:

Enumeration value 'MyBaz' not handled in switch

Derleyicinin ortaya çıkarılan vakaları tespit etmesine izin vermek default, ilk başta sorunuza ilham veren ulaşılamayan davaya olan ihtiyacı büyük ölçüde ortadan kaldırmasıdır .


2
Tamam, beni ikna ettiniz :) Kod kapsamı numaralarında göçük kabul etmem gerekecek.
sd

@st Bu kodu test edememeniz için hiçbir neden yok. Numaralandırmanızda koşullu olarak ekstra bir değer derleyen bir test derlemesi yapın ve ardından bunu kullanan bir birim testi yazın. Belki de bu ideal değildir, ancak normalde asla ulaşılamayacak olan kodu test etmeniz gereken tek durum muhtemelen bu değildir.
Caleb

Veya, numaralandırma türünüze numarasız bir değer döküm ve bunu kullanın.
Mawg, Monica'nın

5

Ben sadece bu sabah bu konuda bir iş arkadaşı ile konuşuyordum - bu gerçekten talihsiz, ama bence güvenlik için varsayılanı ele almak iki nedenden dolayı gereklidir:

Birincisi, iş arkadaşınızın bahsettiği gibi, numaralandırmaya eklenen yeni değerlere karşı kodu geleceğe kanıtlar. Bu bir olasılık gibi görünebilir veya görünmeyebilir, ancak her zaman oradadır.

Daha da önemlisi, dile / derleyiciye bağlı olarak, anahtarlanan değişkeninizde enum üyesi olmayan değerlere sahip olmak mümkün olabilir. Örneğin, C # ile:

MyEnum myEnum = (MyEnum) 3; // This could come from anywhere, maybe parsed from text?
// ... code goes on for a while

switch ( myEnum )
{
    case MyEnum.A:
        // ... handle A case
        break;
    case MyEnum.B:
        // ... handle B case
        break;
}

// ... code that expects either A or B to have happened

Basit case default:olanı ekleyerek ve bir istisna atarak kendinizi "hiçbir şeyin" olmadığı, ancak "bir şeyin" olması gereken bu garip duruma karşı korudunuz.

Ne yazık ki, temelde artık bir anahtar ifadesi yazdığım zaman, çünkü bir enum vakalarını kontrol ediyorum. Gerçekten "varsayılan olarak atmak" davranışı dil kendisi tarafından uygulanmasını isterdim (en azından bir anahtar kelime ekleyerek).


3

Hiçbir zaman ulaşmayı beklemeseniz bile Varsayılan bir vaka eklemek iyi bir şey olabilir. Kodunuz, programın ilerleyen bölümlerinden ziyade hemen "Bu olmamalı" bir istisna atarsa, bazı gizemli istisnaları atar veya beklenmedik sonuçları hatasız döndürürse hata ayıklamayı çok daha kolay hale getirecektir.


2

Diyorum:

Öğesine başka bir tür eklemeyi deneyin MyEnum. Ardından bu satırı değiştirin:

MyEnum myEnum = GetMyEnum();

için

MyEnum myEnum = SomethingElse;

Ardından kodunuzu varsayılan vaka ile ve varsayılan vaka olmadan çalıştırın . Hangi davranışı tercih edersin?

Varsayılan duruma sahip olmak, NULLdeğerleri yakalamak ve önlemek için de yararlı olabilir NullPointerExceptions.


-1

Varsayılan durumda ısrar ederek mach süresinin nasıl kaydedilebileceği hakkında bir fikriniz varsa, soruyu sormanıza gerek yoktur. Bir hata durumunda sessizce hiçbir şey yapmak kabul edilemez - asla gerçekleşmemesi gereken istisnaları sessizce mi yakalarsınız? Sizi izleyen programcılar için "mayın" ı bırakmak, benzer şekilde kabul edilemez.

Kodunuz hiçbir zaman değiştirilmeyecek veya değiştirilmeyecekse ve% 100 hata içermiyorsa, varsayılan durumu hariç tutmak doğru olabilir.

Ada (sağlam programlama dillerinin dedesi), tüm numaralandırmalar örtülmedikçe veya varsayılan bir işleyici yoksa, bu özellik her dil için istek listemde değildir. Ada kodlama standardımız, numaralandırma anahtarları ile tüm değerlerin açık bir şekilde işlenmesinin, varsayılan olmadan bu durumu ele almanın tercih edilen yolu olduğunu belirtir.


Neden tüm -1'ler?
mattnz

2
Seni -1 yapmadım, ama senin tutumun yüzünden olacağını düşünüyorum;)
Friek
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.