สลับคำสั่ง - จัดการกรณีเริ่มต้นเมื่อไม่สามารถเข้าถึงได้


15

ถ้าฉันใช้คำสั่ง switch เพื่อจัดการค่าจาก enum (ซึ่งเป็นของชั้นเรียนของฉัน) และฉันมีเคสสำหรับค่าที่เป็นไปได้แต่ละอัน - มันคุ้มค่าที่จะเพิ่มรหัสเพื่อจัดการกับเคส "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() 
}

ฉันไม่คิดว่าเป็นเพราะรหัสนี้ไม่สามารถเข้าถึงได้ (แม้จะมีการทดสอบหน่วย) เพื่อนร่วมงานของฉันไม่เห็นด้วยและคิดว่าสิ่งนี้ปกป้องเราจากพฤติกรรมที่ไม่คาดคิดที่เกิดจากค่าใหม่ที่เพิ่มเข้ามาใน MyEnum

ชุมชนพูดว่าอย่างไร


สมมติว่า MyEnum เป็นประเภทที่ไม่สามารถลบล้างได้
sd

3
"วันนี้" ไม่สามารถยกเลิกได้ จะเกิดอะไรขึ้นในวันพรุ่งนี้เมื่อคุณไม่ได้ดูแลรหัสอีกต่อไป หรือจะเพิ่มเมื่อ "MyBiz" ใน enum แต่ไม่ใช่ในกรณีใด ความคิดเห็นของ Caleb เกี่ยวกับการบำรุงรักษานั้นช่างแสนดี

1
สอนคอมไพเลอร์ของคุณว่าเป็นข้อผิดพลาดร้ายแรงหากมีสวิตช์ไม่ครอบคลุมทุกกรณี

จะเกิดอะไรขึ้นถ้ามีคนโยนค่าที่ไม่ถูกต้องให้MyEnumผ่านสวิตช์ของคุณ
Mawg กล่าวว่าคืนสถานะโมนิก้า

1
ภาษาอะไร? หาก Java คุณควรใส่วิธีใน Enum และเรียกมันว่า (polymorphism) โดยกำจัดswitchคำสั่งทั้งหมด
949300

คำตอบ:


35

การรวมตัวพิมพ์เริ่มต้นไม่ได้เปลี่ยนวิธีการทำงานของรหัสของคุณ แต่จะทำให้รหัสของคุณสามารถบำรุงรักษาได้มากขึ้น ด้วยการทำให้ตัวแบ่งรหัสในวิธีที่ชัดเจน (บันทึกข้อความและส่งข้อยกเว้น) คุณจะรวมลูกศรสีแดงขนาดใหญ่สำหรับนักศึกษาฝึกงานที่ บริษัท ของคุณว่าจ้างในช่วงฤดู ลูกศรบอกว่า: "เฮ้คุณ! ใช่ฉันกำลังพูดกับคุณ! ถ้าคุณกำลังจะเพิ่มมูลค่าอื่นให้กับ enum คุณควรเพิ่มเรื่องที่นี่ด้วย" ความพยายามพิเศษนั้นอาจเพิ่มสองสามไบต์ในโปรแกรมที่คอมไพล์ซึ่งเป็นสิ่งที่ต้องพิจารณา แต่มันจะช่วยใครซักคน (อาจเป็นอนาคตของคุณ) บางแห่งระหว่างหนึ่งชั่วโมงถึงหนึ่งวันที่ไม่มีรอยขีดข่วน


อัปเดต:สถานการณ์ที่อธิบายข้างต้นคือการป้องกันค่าที่เพิ่มเข้ามาในการแจงนับในเวลาต่อมานอกจากนี้ยังสามารถจับได้โดยคอมไพเลอร์ เสียงดังกังวาน (และ gcc ฉันคิดว่า) โดยค่าเริ่มต้นจะออกคำเตือนหากคุณเปิดประเภทที่ระบุ แต่ไม่มีกรณีที่ครอบคลุมทุกค่าที่เป็นไปได้ในการแจงนับ ตัวอย่างเช่นหากคุณลบdefaultกรณีออกจากสวิตช์และเพิ่มค่าใหม่MyBazให้กับการแจงนับคุณจะได้รับคำเตือนที่แจ้งว่า:

Enumeration value 'MyBaz' not handled in switch

การให้คอมไพเลอร์ตรวจพบเคสที่ไม่ได้เปิดก็คือมันไม่จำเป็นต้องใช้defaultเคสที่เข้าถึงไม่ได้ซึ่งเป็นแรงบันดาลใจให้กับคำถามของคุณตั้งแต่แรก


2
ตกลงคุณเชื่อฉัน :) ฉันจะต้องยอมรับบุ๋มในหมายเลขความครอบคลุมรหัสของฉัน
sd

@st มีเหตุผลที่คุณไม่สามารถทดสอบรหัสนั้นได้ เพียงสร้างแบบทดสอบที่รวบรวมเงื่อนไขในค่าพิเศษในการแจงนับของคุณแล้วเขียนการทดสอบหน่วยที่ใช้ บางทีนั่นอาจไม่เหมาะ แต่อาจไม่ใช่กรณีเดียวที่คุณต้องทดสอบโค้ดที่ปกติจะไม่สามารถเข้าถึงได้
Caleb

หรือคุณใช้ค่า non-enum กับชนิด enum ของคุณและใช้ค่านั้น
Mawg พูดว่าคืนสถานะโมนิก้า

5

ฉันเพิ่งพูดคุยกับเพื่อนร่วมงานเกี่ยวกับเช้านี้เช่นกัน - มันโชคร้ายจริงๆ แต่ฉันคิดว่าการจัดการค่าเริ่มต้นนั้นจำเป็นสำหรับความปลอดภัยด้วยเหตุผลสองประการ:

ก่อนอื่นตามที่เพื่อนร่วมงานของคุณกล่าวถึงมันจะเป็นการพิสูจน์รหัสในอนาคตกับค่าใหม่ที่เพิ่มเข้ามาใน enum สิ่งนี้อาจจะใช่หรือไม่ใช่ แต่ก็เป็นไปได้เสมอ

ที่สำคัญกว่านั้นขึ้นอยู่กับภาษา / คอมไพเลอร์อาจมีค่าที่ไม่ใช่สมาชิกของ enum ในตัวแปรที่คุณสลับ ตัวอย่างเช่นใน 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

ด้วยการเพิ่มcase default:ข้อยกเว้นที่เรียบง่ายและการขว้างปาคุณได้ป้องกันตัวคุณเองจากคดีแปลก ๆ ที่ "ไม่มีอะไร" เกิดขึ้น แต่ควรมีบางสิ่งที่เกิดขึ้น

แต่น่าเสียดายที่โดยทั่วไปเมื่อใดก็ตามที่ฉันเขียนคำสั่ง switch อีกต่อไปก็เป็นเพราะฉันกำลังตรวจสอบกรณีของ enum ฉันต้องการให้มีการบังคับใช้พฤติกรรม "โยนตามค่าเริ่มต้น" ด้วยตัวเอง (อย่างน้อยก็โดยการเพิ่มคำหลัก)


3

การเพิ่มตัวอักษรเริ่มต้นแม้ว่าคุณจะไม่เคยคาดหวังว่ามันจะเป็นสิ่งที่ดีก็ตาม มันจะทำให้การดีบักง่ายขึ้นมากหากรหัสของคุณมีข้อยกเว้น "นี่ไม่ควรเกิดขึ้น" ในทันทีแทนที่จะเป็นในภายหลังในโปรแกรมดึงข้อยกเว้นลึกลับบางอย่างหรือส่งคืนผลลัพธ์ที่ไม่คาดคิดโดยไม่มีข้อผิดพลาด


2

ฉันพูด:

MyEnumลองเพิ่มอีกชนิดหนึ่งที่จะ จากนั้นเปลี่ยนบรรทัดนี้:

MyEnum myEnum = GetMyEnum();

ถึง

MyEnum myEnum = SomethingElse;

จากนั้นเรียกใช้รหัสของคุณด้วยตัวพิมพ์ใหญ่และไม่ใช้ตัวพิมพ์ใหญ่ คุณชอบพฤติกรรมแบบไหน

มีกรณีที่เริ่มต้นยังสามารถเป็นประโยชน์สำหรับการวางกับดักค่านิยมและการป้องกันNULLNullPointerExceptions


-1

หากคุณมีความคิดใด ๆ ว่าสามารถประหยัดเวลาจักรได้อย่างไรโดยยืนยันในกรณีเริ่มต้นคุณไม่จำเป็นต้องถามคำถาม การไม่ทำอะไรเลยในสภาวะของความผิดพลาดอย่างเงียบ ๆ นั้นเป็นสิ่งที่ยอมรับไม่ได้คุณจับข้อยกเว้นที่ไม่ควรเกิดขึ้นในใจ ปล่อย "เหมือง" สำหรับโปรแกรมเมอร์ที่ติดตามคุณซึ่งยอมรับไม่ได้ในทำนองเดียวกัน

หากรหัสของคุณจะไม่มีการเปลี่ยนแปลงหรือแก้ไขและไม่มีข้อผิดพลาด 100% การออกกรณีที่เป็นค่าเริ่มต้นอาจใช้ได้

Ada (ปู่ของภาษาการเขียนโปรแกรมที่มีประสิทธิภาพ) จะไม่รวบรวมสวิตช์บน enum ยกเว้นว่า enums ทั้งหมดได้รับการคุ้มครองหรือมีตัวจัดการเริ่มต้น - คุณลักษณะนี้อยู่ในรายการที่ต้องการสำหรับทุกภาษา รหัสมาตรฐาน Ada ของเราระบุว่าเมื่อเปิดสวิตช์การจัดการค่าทั้งหมดอย่างชัดเจนโดยไม่มีค่าเริ่มต้นเป็นวิธีที่เหมาะสมในการจัดการสถานการณ์นี้


ทำไม -1 ทั้งหมดของ?
mattnz

2
ฉันไม่ได้ -1 คุณ แต่ฉันคิดว่ามันจะเป็นเพราะทัศนคติของคุณ;)
ศุกร์
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.