2010-03-19 18 views
19

Đi một số mã nhưNếu bạn luôn viết mã cho các trường hợp khác "không bao giờ có thể xảy ra"?

if (person.IsMale()) { 
    doGuyStuff(); 
} else { 
    doGirlStuff(); 
} 

này nên được ghi vào kiểm tra một cách rõ ràng nếu person.isFemale(), và sau đó thêm một ai khác mới mà ném một ngoại lệ? Có lẽ bạn đang kiểm tra các giá trị trong một enum, hoặc một cái gì đó như thế. Bạn nghĩ rằng không ai sẽ thêm các yếu tố mới vào enum, nhưng ai biết được? "Không bao giờ có thể xảy ra" giống như những từ cuối cùng nổi tiếng.

+7

Never say never: Tôi đọc một câu chuyện mới đây về một người Down Under với một tình huống không xác định 'Down Under', người đã kiến ​​nghị thành công cho chỉ định giới tính chính thức của 'không được chỉ định' –

+0

Yep. Nếu bạn đang làm việc cho Tổng điều tra năm 2010, xử lý, không ném, nam, nữ, và khác. Đối với các tình huống khác và enums khác, thời gian cần để hỏi là tốt hơn dành viết "ném". – Potatoswatter

+8

Giới tính không thực sự là 0 (nữ) hoặc 1 (nam), phạm vi của nó là từ 0.0 đến 1.0. Trong thực tế, điều đó có thể sai, giới tính là một số phức ở đâu đó giữa i, i^2, và 7. – Juliet

Trả lời

9

Tôi nghĩ bạn đã trả lời câu hỏi của riêng bạn. Nếu bạn biết bạn sẽ không bao giờ nhìn thấy giá trị bổ sung:

bool isSet = ... 
if (isSet) 
{ 
    return foo; 
} 
return bar; 

... thì đừng bận tâm. Nhưng nếu có cơ hội có thể có nhiều hơn hai giá trị có thể, hãy tự che đậy. Bạn (hoặc người lập trình bảo trì hai năm xuống đường) sẽ biết ơn vì điều đó.

+1

Tôi đồng ý với báo trước rằng để bạn "biết" rằng bạn sẽ không bao giờ thấy các giá trị bổ sung, nó phải là * không thể * đối với một người nào đó để thêm các giá trị không mong muốn. Booleans là một ví dụ tuyệt vời, bởi vì không có vấn đề gì, không ai có thể tạo ra một boolean không đúng hay sai. Các giá trị 'Enum', mặt khác, có thể được sửa đổi bởi các lập trình viên khác (hoặc bạn!) Trong tương lai, có nghĩa là bạn không bao giờ có thể chắc chắn 100% rằng một giá trị mới sẽ không được thêm vào. –

+0

@Joe Carnahan - Bạn không bao giờ biết. Nếu ai đó cuối cùng thực hiện phổ biến rộng rãi, chúng ta có thể thấy, đúng, sai, có lẽ? – tjameson

+0

http://thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx –

8

Tôi tìm thấy 'không bao giờ có thể xảy ra' âm thanh tốt cho đến khi nó cắn bạn trong những tháng sau đó, sau khi một đồng nghiệp đã thêm mã, phá vỡ mã ban đầu của bạn. Vì vậy, đối với bản thân mình, tôi sẽ chắc chắn rằng nếu của tôi là rắn ngay cả khi nó có vẻ không thể.

1

Tôi đoán nó phụ thuộc vào loại đối tượng của bạn. Nếu nó là đúng boolean (hoặc nhị phân nói chung), sau đó, như bạn đã đoán, thử nghiệm thứ hai là dư thừa. Bất kỳ trường hợp nào khác, thử nghiệm thứ hai sẽ được thực hiện.

Tuy nhiên, ngay cả trong điều kiện này, bạn có thể có "lối tắt tinh thần" trong việc bảo vệ mở rộng trong tương lai của miền đối tượng - chỉ giả định rằng chỉ có một giá trị là giá trị "true" và tất cả các giá trị khác được mặc định giá trị "false".

8

Nếu bạn đọc kỹ một số phương pháp chính thức, bạn nên làm điều này.

  1. Xác định hậu điều kiện

    isMale && doGuyStuff || isFemale && doGirlStuff. 
    
  2. Rút ra một số báo cáo ứng cử viên đó sẽ dẫn đến bài tình trạng này

    if isMale: doGuyStuff 
    

    Đó provably dẫn đến một số hậu điều kiện

    if isFemale: doGirlStuff 
    

    Điều đó có thể dẫn đến một số tình trạng sau

    Lưu ý rằng đơn đặt hàng không quan trọng. Thật vậy, nó đơn giản hơn nếu bạn loại bỏ bất kỳ giả định đặt hàng nào.

  3. Bạn gió lên với những điều sau:

    if isMale: doGuyStuff 
    elif isFemale: doGirlStuff 
    

    Lưu ý rằng không có sử dụng hợp lý cho một khoản else. Bạn sẽ không bao giờ - trong một dẫn xuất chính thức - lấy một mệnh đề else. Bạn sẽ luôn có các điều kiện là những tuyên bố tích cực: a && b || c && d các loại sự vật. Hiếm khi nó sẽ là a && b || !a && c, nhưng thậm chí sau đó, bạn thường bị gió với điều kiện rõ ràng !a.

Chính thức, mệnh đề "không thể khác" nên được giới hạn để thực hiện một việc như sau.

if isMale: doGuyStuff 
    elif isFemale: doGirlStuff 
    else: 
     raise HorrifyingSituationError 

Nếu bạn đã từng đưa ra HorrifyingSituationError, điều đó có nghĩa là bạn đã thực hiện sai phép toán và trích xuất không chính xác các câu lệnh từ các điều kiện. Hoặc bạn đã xác định không chính xác tình trạng sau ở nơi đầu tiên.

Dù bằng cách nào, chương trình được thiết kế sai một cách sâu sắc và tuyệt đối. Nói chung, đây không phải là một bất ngờ. Nó thường thất bại ngoạn mục trong lần đầu tiên bạn thử kiểm tra nó. Trừ khi (vì nó thường xảy ra), bạn đã chọn dữ liệu thử nghiệm phản ánh các lỗi trong định nghĩa ban đầu của bạn về điều kiện sau. Thậm chí sau đó, một khi bạn gặp phải ngoại lệ này, bạn có thể dễ dàng theo dõi nó và sửa chữa nó vĩnh viễn.

+0

Bạn cũng có thể thể hiện chính thức điều này với các điều kiện tiên quyết, hoặc Thiết kế theo Hợp đồng, xác định rằng điều kiện tiên quyết là '.isMale() || .isFemale() '. Nó thường là một ý tưởng tốt để kiểm tra điều kiện tiên quyết. –

1

@Michael Petrotta - đoạn mã của bạn không đúng, vì hành động DoY() được bỏ qua giá trị thực của điều kiện.

(xin lỗi, không thể thêm bình luận nào ...)

+1

Đúng vậy, cảm ơn. Đã sửa. Dưới đây là một upvote; chào mừng bạn đến với ý kiến. –

+0

Cảm ơn, Michael! – ysap

3

tôi không nhận được để làm mã hóa cho công ty của tôi, nhưng đã có nhiều trường hợp mà các lập trình viên của chúng tôi đã được mã hóa mọi thứ cho trường hợp đó rằng sẽ không bao giờ xảy ra và nó có ích khi cố gắng khắc phục sự cố của khách hàng được báo cáo. Nó dường như xảy ra thường xuyên với mã chúng tôi nhận được từ các dự án ở nước ngoài của chúng tôi.

Khi một khách hàng gọi điện và nói "Hey Tôi nhận được một 'lỗi gõ không được phép', và nói rằng 'không được phép loại vịt', chúng tôi đã nhanh chóng tìm ra nguyên nhân của vấn đề và đã có thể giải quyết nó.

0

Nếu nó không bao giờ có thể xảy ra sau đó bạn sẽ không cần phải viết mã cho nó

1

Hãy nhớ rằng enums trong C# có khả năng cắn bạn:.!

enum SwitchPosition 
{ 
    Off = 0, 
    On = 1 
} 

void SetLightStatus(SwitchPosition pos) 
{ 
    switch (pos) 
    { 
     case On: 
      TurnLightOn(); 
      break; 
     case Off: 
      TurnLightOff(); 
      break; 
     default: 
      // Fugedaboudit -- will never happen, right? 
    } 
} 

sai Calling SetLightPosition(2); là hợp pháp và sẽ giảm thông qua các trường hợp trong câu lệnh chuyển đổi đó. o ném một số HorrifyingSituationError theo đề xuất của S. Lott.

+1

bạn không phải lo lắng về điều đó trong một ngôn ngữ như Java mà thực sự là loại an toàn nơi Enums là đối tượng lớp học đầu tiên và không chỉ cú pháp đường cho một int –

+0

Điểm tốt, tôi đã chỉnh sửa để xác định C# là ngôn ngữ tôi 'm cảnh báo về. –

0

Cá nhân, tôi sẽ viết những dòng else như:

} else /*if (person.IsFemale())*/ { 

này sidesteps phải chạy chức năng (tôi ghét phải lãng phí thời gian chạy nó nếu kết quả của nó không cần thiết) nhưng lá quan trọng tài liệu cho các nhà phát triển trong tương lai. Bây giờ rõ ràng rằng nhánh này của điều kiện bao gồm trường hợp IsFemale (cụ thể), chứ không phải trường hợp !IsMale (nói chung). Về cơ bản, bạn đang đưa ra các giả định của mình "to", điều này làm cho nó ít có khả năng là những thay đổi trong tương lai sẽ hiểu sai những gì bạn đang làm và phá vỡ mã của bạn.

Trong hệ thống nhúng của chúng tôi, có thể khó phân tích và gỡ lỗi các lỗi vì vậy chúng tôi thường bao gồm các câu lệnh "không thể" else và khiến chúng nhả ra thông báo lỗi và ném ngoại lệ. Điều này thường bị hạn chế đối với các bản xây dựng phát triển và khi mã ổn định, chúng sẽ bị xóa.

1

Nếu bạn muốn chỉ ra một khối mã rằng "không thể xảy ra", sử dụng

assert (false); 
4

Nếu nó KHÔNG THỂ xảy ra trong sản xuất (nhưng có thể xảy ra trong quá trình phát triển), tôi sử dụng assert:

Nếu nó KHÔNG NÊN xảy ra trong sản xuất, nhưng nó có thể là có thể, tôi hoặc là trả về một lỗi hoặc ném một ngoại lệ ion.

Nhân tiện, đây là mẹo nhỏ gọn C++ nhỏ nhặt mà tôi đã chọn ở đâu đó; vì nhiều macro ASSERT sẽ hiển thị biểu hiện của họ trong một hộp thông báo nếu khẳng định là không đúng sự thật, bạn có thể sử dụng các hình thức sau đây cho các chi nhánh mà không bao giờ nên được thực hiện:

if (person.IsMale()) 
{ 
    AdmitEntranceToManCave(); 
} 
else 
{ 
    ASSERT(!"A female has gotten past our defenses. EVERYBODY PANIC!"); 
} 

Chuỗi đánh giá lại theo nghĩa đen đến một (không NULL) địa chỉ, đó là TRUE. Vì vậy, sử dụng toán tử NOT logic làm cho nó sai.

0

Câu hỏi phụ thuộc vào ngữ cảnh của bạn - có ai khác sẽ có thể mở rộng đối tượng Người của bạn không? Khi android trở thành pháp nhân, bạn có thể thấy rằng cả hai isMale() và isFemale() có thể là false.

Điều này đặc biệt phù hợp nếu mã bạn đang viết là một mô-đun sẽ được sử dụng bởi những người bên ngoài nhóm của bạn. Tất nhiên, trong trường hợp đó, bạn có thể tiến thêm một bước nữa, bỏ qua mã hóa cứng nếu thử nghiệm và gọi doGenderStuff() trên một đối tượng được tạo bởi nhà máy thích hợp ...

0

Vì có quá nhiều câu trả lời, tôi ' sẽ chỉ cho bạn thấy những gì làm quá nó trông giống như: (trong C++)

if(!DoOperation()) 
{ 
    // Allocate for a message 
    char * pMsg = new char[256]; 
    // Make sure the memory was allocated 
    if(!pMsg) 
    { 
     cout << PREDEFINED_OUT_OF_MEMORY_MESSAGE << endl; 
     exit(0); 
    } 

    if(!strcpy(pMsg,"Operation failed!")) 
    { 
     cout << PREDEFINED_STRCPY_FAILED_MESSAGE << endl; 
     exit(0); 
    } 

    // Now let the user know there was an error 
    ErrorDetailStructure * pError = new ErrorDetailStructure(); 
    if(!pError) 
    { 
     cout << PREDEFINED_OUT_OF_MEMORY_MESSAGE << endl; 
     exit(0); 
    } 

    // Copy the message to the error structure 
    if(!strcpy(pError->pMessage,pMsg)) 
    { 
     cout << PREDEFINED_STRCPY_FAILED_MESSAGE << endl; 
     exit(0); 
    } 

    // Alert the user - yes, ErrorDetailsStructure 
    // overloads operator<< 
    cout << pError; 

    delete pError; // the destructor frees pMessage member 

    // Now we need to log this error 
    some_file_pointer * pFile = OpenAFilePointer("/root/logfile"); 

    if(!some_file_pointer) 
    { 
     cout << PREDEFINED_OPEN_FILE_ERROR_MESSAGE << endl; 
     exit(0); 
    } 

    some_file_pointer->WriteError("Something went wrong. Guess what it was."); 

    // Don't forget to free some_file_pointer 
    delete some_file_pointer; 

    exit(0); // Just quit. Give up. 
} 

Tôi đã có rất nhiều niềm vui với điều này. Có rất nhiều vấn đề với điều này (và thiết kế rất tệ) mà tôi có một tiếng cười tốt khi viết nó.

0

tôi sẽ giữ các mã như sạch và ngắn càng tốt, và sau đó thêm khẳng định đến những nơi mà không gây ô nhiễm vệ sinh :)

if(male) 
{ 
    ... 
} 
else 
{ 
    ... 
} 

// other stuff that nobody cares about... 
assert(male||female); 
Các vấn đề liên quan