beralih pernyataan - menangani kasus default saat tidak dapat dihubungi

14

Jika saya menggunakan pernyataan switch untuk menangani nilai dari enum (yang dimiliki oleh kelas saya) dan saya memiliki case untuk setiap nilai yang mungkin - apakah ada baiknya menambahkan kode untuk menangani case "default"?

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

Saya tidak berpikir itu karena kode ini tidak pernah dapat dicapai (bahkan dengan tes unit). Rekan kerja saya tidak setuju dan menganggap ini melindungi kami dari perilaku tak terduga yang disebabkan oleh nilai-nilai baru yang ditambahkan ke MyEnum.

Bagaimana kabarmu, komunitas?

sd
sumber
Katakanlah MyEnum adalah tipe yang tidak dapat dibatalkan.
sd
3
"Hari ini" tidak dapat dibatalkan. Bagaimana dengan besok ketika Anda tidak mempertahankan kode lagi. Atau bagaimana ketika "MyBiz" ditambahkan ke enum tetapi tidak demikian? Komentar Caleb tentang pemeliharaan sangat erat.
1
Ajari kompiler Anda bahwa itu adalah kesalahan fatal jika ada saklar yang tidak mencakup semua kasus.
Bagaimana jika seseorang melemparkan nilai yang tidak valid untuk MyEnumkemudian melewati sakelar Anda?
Mawg mengatakan mengembalikan Monica
1
Bahasa apa? Jika Java, Anda harus meletakkan metode di dalam Enum dan cukup menyebutnya (polimorfisme), menghilangkan switchpernyataan sepenuhnya.
user949300

Jawaban:

34

Menyertakan case default tidak mengubah cara kode Anda bekerja, tetapi itu membuat kode Anda lebih mudah dikelola. Dengan membuat pemecah kode dengan cara yang jelas (mencatat pesan dan melemparkan pengecualian), Anda menyertakan panah merah besar untuk pekerja magang yang disewa perusahaan Anda musim panas mendatang untuk menambahkan beberapa fitur. Panah mengatakan: "Hei, kamu! Ya, saya sedang berbicara dengan ANDA! Jika Anda akan menambahkan nilai lain ke enum, Anda sebaiknya menambahkan kasus di sini juga." Upaya ekstra itu dapat menambahkan beberapa byte ke program yang dikompilasi, yang merupakan sesuatu yang perlu dipertimbangkan. Tapi itu juga akan menyelamatkan seseorang (mungkin bahkan masa depan Anda) di suatu tempat antara satu jam dan satu hari dari menggaruk-garuk kepala tidak produktif.


Pembaruan: Situasi yang dijelaskan di atas, yaitu melindungi terhadap nilai-nilai yang ditambahkan ke enumerasi di beberapa waktu kemudian, juga dapat ditangkap oleh kompiler. Dentang (dan gcc, saya pikir) secara default akan mengeluarkan peringatan jika Anda mengaktifkan jenis yang disebutkan tetapi tidak memiliki kasus yang mencakup setiap nilai yang mungkin dalam enumerasi. Jadi, misalnya, jika Anda menghapus defaultkasing dari sakelar dan menambahkan nilai baru MyBazke enumerasi, Anda akan mendapatkan peringatan yang mengatakan:

Enumeration value 'MyBaz' not handled in switch

Membiarkan kompiler mendeteksi kasus yang tidak terungkap adalah bahwa sebagian besar menghilangkan kebutuhan untuk defaultkasus yang tidak terjangkau yang menginspirasi pertanyaan Anda.

Caleb
sumber
2
Ok, Anda sudah meyakinkan saya :) Saya hanya harus menerima lekuk di nomor cakupan kode saya.
sd
@st Tidak ada alasan bahwa Anda tidak dapat menguji kode itu. Lakukan saja uji coba bangunan yang mengkompilasi syarat dalam nilai tambahan dalam enumerasi Anda, dan kemudian tulis unit test yang menggunakannya. Mungkin itu tidak ideal, tetapi mungkin itu bukan satu-satunya kasus di mana Anda perlu menguji kode yang biasanya tidak akan pernah tercapai.
Caleb
Atau, Anda memberikan nilai non-enum ke tipe enum Anda dan menggunakannya.
Mawg mengatakan mengembalikan Monica
5

Saya baru saja berbicara dengan rekan kerja tentang hal ini pagi ini - sangat disayangkan, tetapi saya pikir penanganan standar diperlukan untuk keselamatan, karena dua alasan:

Pertama, seperti rekan kerja Anda sebutkan, itu membuktikan di masa depan kode terhadap nilai-nilai baru yang ditambahkan ke enum. Ini mungkin atau mungkin tidak tampak seperti suatu kemungkinan, tetapi selalu ada.

Lebih penting lagi, tergantung pada bahasa / kompiler, dimungkinkan untuk memiliki nilai-nilai yang bukan anggota enum dalam variabel diaktifkan Anda. Misalnya, dalam C #:

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

Dengan menambahkan case default:pengecualian sederhana dan melemparkan, Anda telah melindungi diri terhadap kasus aneh ini di mana "tidak ada" yang terjadi tetapi "sesuatu" seharusnya terjadi.

Sayangnya, pada dasarnya setiap kali saya menulis pernyataan beralih lagi, itu karena saya sedang memeriksa kasus enum. Saya benar-benar berharap perilaku "melempar secara default" dapat ditegakkan oleh bahasa itu sendiri (setidaknya dengan menambahkan kata kunci).

Chris Phillips
sumber
3

Menambahkan kasing standar meskipun Anda tidak pernah berharap untuk mencapainya, itu bisa menjadi hal yang baik. Ini akan membuat proses debug jauh lebih mudah jika kode Anda melontarkan perkecualian "Ini seharusnya tidak terjadi" segera daripada nanti dalam program, menyadap beberapa pengecualian misterius atau mengembalikan hasil yang tidak terduga tanpa kesalahan.

Ryathal
sumber
2

Saya katakan:

Coba tambahkan jenis lain ke MyEnum. Kemudian ubah baris ini:

MyEnum myEnum = GetMyEnum();

untuk

MyEnum myEnum = SomethingElse;

Kemudian jalankan kode Anda dengan kasing standar dan tanpa kasing standar. Perilaku mana yang Anda sukai?

Memiliki case default juga dapat berguna untuk menjebak NULLnilai dan mencegahnya NullPointerExceptions.

FrustratedWithFormsDesigner
sumber
-1

Jika Anda tahu bagaimana waktu mesin dapat dihemat dengan bersikeras pada kasus default, Anda tidak perlu mengajukan pertanyaan. Diam-diam melakukan apa pun dalam kondisi kesalahan tidak dapat diterima - apakah Anda diam-diam menangkap pengecualian yang seharusnya tidak pernah terjadi? Meninggalkan "ranjau" untuk pemrogram yang mengikuti Anda, juga tidak dapat diterima.

Jika kode Anda tidak akan pernah diubah atau dimodifikasi, dan 100% bebas bug, meninggalkan case default mungkin OK.

Ada (kakek dari bahasa pemrograman yang kuat) tidak akan mengkompilasi switch pada enum, kecuali semua enum tercakup atau ada pengendali default - fitur ini ada dalam daftar keinginan saya untuk setiap bahasa. Standar pengkodean Ada kami menyatakan bahwa dengan mengaktifkan enum, penanganan eksplisit semua nilai, tanpa standar adalah cara yang lebih disukai untuk menangani situasi ini.

mattnz
sumber
Kenapa semua -1?
mattnz
2
Saya tidak -1 Anda, tetapi saya pikir itu karena sikap Anda;)
Friek