câu lệnh chuyển đổi - xử lý trường hợp mặc định khi không thể đạt được


14

Nếu tôi đang sử dụng câu lệnh chuyển đổi để xử lý các giá trị từ enum (thuộc sở hữu của lớp tôi) và tôi có một trường hợp cho mỗi giá trị có thể - có đáng để thêm mã để xử lý trường hợp "mặc định" không?

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

Tôi không nghĩ rằng đó là vì mã này không bao giờ có thể đạt được (ngay cả với các bài kiểm tra đơn vị). Đồng nghiệp của tôi không đồng ý và nghĩ rằng điều này bảo vệ chúng tôi trước những hành vi bất ngờ gây ra bởi các giá trị mới được thêm vào MyEnum.

Bạn nói gì, cộng đồng?


Giả sử MyEnum là một loại không thể rỗng.
sd

3
"Hôm nay" không phải là vô giá trị. Còn ngày mai thì sao khi bạn không duy trì mã nữa. Hoặc những gì về khi "MyBiz" được thêm vào enum nhưng không phải là trường hợp? Nhận xét của Caleb về bảo trì là rất lành mạnh.

1
Dạy cho trình biên dịch của bạn rằng đó là một lỗi nghiêm trọng nếu có một công tắc không bao gồm tất cả các trường hợp.

Điều gì xảy ra nếu ai đó đưa ra một giá trị không hợp lệ để MyEnumsau đó chuyển nó qua công tắc của bạn?
Mawg nói rằng phục hồi Monica

1
Ngôn ngữ nào? Nếu Java, bạn nên đặt một phương thức bên trong Enum và chỉ cần gọi nó (đa hình), loại bỏ switchhoàn toàn câu lệnh.
dùng949300

Câu trả lời:


34

Bao gồm trường hợp mặc định không thay đổi cách mã của bạn hoạt động, nhưng nó làm cho mã của bạn dễ bảo trì hơn. Bằng cách làm cho mã bị phá vỡ theo một cách rõ ràng (ghi lại một thông báo và ném một ngoại lệ), bạn bao gồm một mũi tên lớn màu đỏ cho nhân viên thực tập mà công ty của bạn thuê vào mùa hè tới để thêm một vài tính năng. Mũi tên nói: "Này, bạn! Vâng, tôi đang nói chuyện với BẠN! Nếu bạn sẽ thêm một giá trị khác vào enum, tốt hơn bạn nên thêm một trường hợp ở đây nữa." Nỗ lực thêm đó có thể thêm một vài byte vào chương trình được biên dịch, đây là điều cần xem xét. Nhưng nó cũng sẽ cứu ai đó (thậm chí là tương lai bạn) ở đâu đó giữa một giờ và một ngày gãi đầu không hiệu quả.


Cập nhật: Tình huống được mô tả ở trên, tức là bảo vệ chống lại các giá trị được thêm vào một bảng liệt kê sau đó, cũng có thể bị trình biên dịch bắt gặp. Clang (và gcc, tôi nghĩ) theo mặc định sẽ đưa ra cảnh báo nếu bạn bật loại liệt kê nhưng không có trường hợp bao gồm mọi giá trị có thể có trong bảng liệt kê. Vì vậy, ví dụ: nếu bạn loại bỏ defaulttrường hợp khỏi công tắc của bạn và thêm một giá trị mới MyBazvào bảng liệt kê, bạn sẽ nhận được một cảnh báo có nội dung:

Enumeration value 'MyBaz' not handled in switch

Để trình biên dịch phát hiện các trường hợp chưa được khám phá là phần lớn sẽ loại bỏ sự cần thiết cho defaulttrường hợp không thể truy cập đó đã truyền cảm hứng cho câu hỏi của bạn ngay từ đầu.


2
Ok, bạn đã thuyết phục tôi :) Tôi sẽ phải chấp nhận vết lõm trong số bảo hiểm mã của tôi.
sd

@st Không có lý do gì mà bạn không thể kiểm tra mã đó. Chỉ cần thực hiện một bản dựng thử nghiệm có điều kiện biên dịch một giá trị bổ sung trong bảng liệt kê của bạn, sau đó viết một bài kiểm tra đơn vị sử dụng nó. Có lẽ điều đó không lý tưởng, nhưng có lẽ đó không phải là trường hợp duy nhất mà bạn cần kiểm tra mã mà thông thường sẽ không bao giờ đạt được.
Caleb

Hoặc, bạn chuyển một giá trị không enum cho loại enum của bạn và sử dụng giá trị đó.
Mawg nói rằng phục hồi Monica

5

Tôi cũng vừa nói chuyện với một đồng nghiệp về sáng nay - thật đáng tiếc, nhưng tôi nghĩ việc xử lý mặc định là cần thiết cho an toàn, vì hai lý do:

Đầu tiên, như đồng nghiệp của bạn đề cập, nó chứng minh mã tương lai chống lại các giá trị mới được thêm vào enum. Điều này có thể hoặc có thể không giống như một khả năng, nhưng nó luôn ở đó.

Quan trọng hơn, tùy thuộc vào ngôn ngữ / trình biên dịch, có thể có các giá trị không phải là thành viên của enum trong biến chuyển đổi của bạn. Ví dụ: trong 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

Bằng cách thêm đơn giản case default:và ném một ngoại lệ, bạn đã tự bảo vệ mình trước trường hợp kỳ lạ này khi "không có gì" xảy ra nhưng "điều gì đó" đáng lẽ phải xảy ra.

Thật không may, về cơ bản bất cứ khi nào tôi viết một tuyên bố chuyển đổi nữa, đó là vì tôi đang kiểm tra các trường hợp của một enum. Tôi thực sự mong muốn hành vi "ném theo mặc định" có thể được thực thi bằng chính ngôn ngữ (ít nhất là bằng cách thêm từ khóa).


3

Thêm một trường hợp mặc định ngay cả khi bạn không bao giờ mong đợi đạt được nó có thể là một điều tốt. Nó sẽ giúp việc gỡ lỗi dễ dàng hơn nhiều nếu mã của bạn ném ngoại lệ "Điều này không nên xảy ra" ngay lập tức thay vì sau đó trong chương trình, tạo ra một ngoại lệ bí ẩn hoặc trả về kết quả không mong muốn mà không gặp lỗi.


2

Tôi nói:

Hãy thử thêm một loại khác vào MyEnum. Sau đó thay đổi dòng này:

MyEnum myEnum = GetMyEnum();

đến

MyEnum myEnum = SomethingElse;

Sau đó chạy mã của bạn với trường hợp mặc định và không có trường hợp mặc định. Bạn thích hành vi nào?

Có trường hợp mặc định cũng có thể hữu ích cho NULLcác giá trị bẫy và ngăn chặn NullPointerExceptions.


-1

Nếu bạn có bất kỳ ý tưởng nào về cách tiết kiệm thời gian mach bằng cách nhấn mạnh vào trường hợp mặc định, bạn sẽ không cần phải đặt câu hỏi. Âm thầm không làm gì trong điều kiện lỗi không được chấp nhận - bạn có âm thầm nắm bắt những ngoại lệ không bao giờ xảy ra không? Để lại "mìn" cho các lập trình viên theo bạn, tương tự không thể chấp nhận được.

Nếu mã của bạn sẽ không bao giờ bị thay đổi hoặc sửa đổi và không có lỗi 100%, việc bỏ qua trường hợp mặc định có thể sẽ ổn.

Ada (ông nội của các ngôn ngữ lập trình mạnh mẽ) sẽ không biên dịch một công tắc trên enum, trừ khi tất cả các enum được bảo hiểm hoặc có một trình xử lý mặc định - tính năng này nằm trong danh sách mong muốn của tôi cho mọi ngôn ngữ. Tiêu chuẩn mã hóa Ada của chúng tôi tuyên bố rằng với các công tắc trên enum, xử lý rõ ràng tất cả các giá trị, không có mặc định là cách ưa thích để xử lý tình huống này.


Tại sao tất cả các -1?
mattnz

2
Tôi đã không -1 bạn, nhưng tôi nghĩ đó là vì thái độ của bạn;)
Friek
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.