2009-05-28 38 views
5
bool fn() 
{ 
    if(something bad happen) 
    return false; 
    .. 
} 


void gn() 
{ 
    assert(something == true); 
    .. 

} 

Khi tôi viết một hàm trong mã sản xuất, cách nào tôi nên chọn?Xác nhận so với trả về false?

Trả lời

5

Assert, ít nhất trong .NET, được sử dụng để thử nghiệm chủ yếu là. sử dụng cụ thể của nó được đặt một cách ngắn gọn here:

Một khẳng định là tốt nhất dùng để thử nghiệm một điều kiện duy nhất khi tất cả các tổ chức sau đây:

* the condition should never be false if the code is correct, 
* the condition is not so trivial so as to obviously be always true, and 
* the condition is in some sense internal to a body of software. 

Trong mã sản xuất, tôi khuyên bạn nên là người đầu tiên phương pháp; hoặc try/catch nếu 'điều gì đó xấu' không bao giờ được mong đợi xảy ra; nếu nó là một điều kiện đặc biệt.

Nếu bạn có bất biến nên luôn luôn hoặc không bao giờ ở đó (bất kể trạng thái của hệ thống), thì đó là một ứng cử viên tốt cho một trường hợp thử nghiệm Assert.

Tôi đã thấy các xác nhận trong mã sản xuất; thông thường trong design-by-contract style code. Tôi thấy chúng thường xuyên hơn trong các bài kiểm tra đơn vị.

1

IMHO, assert là để xác nhận nhà phát triển trong môi trường gỡ lỗi rằng có điều gì đó không mong muốn (sai) đang xảy ra. Không phải tất cả các khẳng định cần phải là quan trọng và nó là vào các nhà phát triển để đưa các khẳng định cho những thất bại thực sự.

Trong chế độ phát hành, bạn chỉ cần trả về false khi lỗi rất quan trọng và không có điểm nào trong việc tiếp tục thực thi.

1

Sử dụng khẳng định khi có điều gì đó không nên xảy ra nếu mã hoạt động bình thường. Ví dụ:

int div(int a, int b) { 
    assert(b != 0); 
    return a/b; 
} 

Ở đây, mã gọi điện có trách nhiệm đảm bảo rằng div() không bao giờ được gọi với tham số thứ hai bằng không. Nếu có, mã của bạn đang ở trạng thái không xác định và sẽ bị chấm dứt.

Sử dụng if() ... trả lại khi có thể xảy ra lỗi có thể được xử lý. Ví dụ, mở một tập tin có thể thất bại và cần được phát hiện và xử lý bởi chương trình - thất bại không đưa chương trình vào một trạng thái không xác định.

0

Câu trả lời đơn giản là cả hai, nhưng câu trả lời thứ hai quan trọng hơn. Xác nhận kiểm tra một giả định thiết kế, do đó trước khi gọi fn() tôi sẽ có các điều kiện trước, ví dụ: một tài nguyên cụ thể có thể có sẵn. Các khẳng định thường sẽ không làm gì trong mã phát hành, mặc dù không nhất thiết. Nếu điều quan trọng là hàm của bạn, gn, yêu cầu một cái gì đó là đúng để làm việc một cách chính xác, nó eithers sử dụng câu lệnh if và trả về và mã lỗi, hoặc ném một ngoại lệ. Assert thường không làm gì trong mã phát hành và do đó chức năng của bạn có thể bị lỗi trong tình huống này.

Xem thêm câu trả lời chi tiết hơn cho this question

0

Đó thực sự phụ thuộc vào môi trường ngôn ngữ/thời gian chạy, và bản chất của lỗi.

Nói chung, chương trình không thể khôi phục từ lỗi xác nhận (tức là nó sẽ bị lỗi). Điều đó có thể hoặc không thể là những gì bạn muốn.

Nếu môi trường của bạn hỗ trợ ngoại lệ, bạn cũng có thể sử dụng các lỗi này, cho phép bạn xử lý lỗi nếu muốn và sẽ hủy bỏ thông báo hữu ích nếu bạn không xử lý lỗi.

Điều "trả về false" là lỗi dễ xảy ra (b/c người quên kiểm tra giá trị trả về), vì vậy tôi chỉ sử dụng nó nếu không có khẳng định cũng như ngoại lệ.

3

Cân nhắc sử dụng ngoại lệ khi "một số điều xấu xảy ra" = một cái gì đó đặc biệt ...

0

Phụ thuộc vào những gì bạn đang kiểm tra. Trong trường hợp đầu tiên nếu điều xấu xảy ra phá vỡ hợp đồng cho lớp học của bạn, hãy ném một ngoại lệ có nghĩa là một cái gì đó cho khách hàng. Trả về false sẽ không cho biết bất kỳ trạng thái nào không chính xác.

3

Sử dụng khẳng định cho cả hai tài liệu và xác nhận rằng các biến thể chương trình (bạn biết nó sẽ luôn đúng) giữ. Trong bất cứ điều gì nhiều hơn một chương trình tầm thường, sự hiểu biết của bạn về vấn đề sẽ phát triển khi bạn viết mã, vì vậy mã cũ hơn có thể có một mô hình khác, và các xác nhận sẽ giúp chọn điều này. Đối với một thứ có thể thay đổi (đặc biệt là ngoài kiểm soát chương trình), bạn cần báo cáo lỗi (ví dụ: giá trị tham số được truyền vào hàm thư viện, tệp không tồn tại), sử dụng cơ chế ưu tiên nền tảng/ngôn ngữ (ngoại lệ). , giá trị trả lại, ...).

+0

Vâng, đó là quan điểm của tôi. Tôi đang sử dụng assert() cuộc gọi để kiểm tra bất biến trong chương trình của tôi. Khi những bất biến như vậy không được tôn trọng, như lời gọi khẳng định tạo ra một coredump cho ứng dụng của tôi (trong khi gỡ lỗi nó), tôi chắc chắn tôi sẽ không bỏ qua vấn đề như vậy. Ngoài ra, tôi mong đợi "các nhà phát triển phụ trách" tiếp theo nhận thấy có điều gì đó không ổn khi ứng dụng bị hỏng ... Trong khi một câu lệnh trả về đơn giản có thể dẫn đến kết xuất một số dòng trong một tệp, thì nhà phát triển có thể tránh. Tôi không có nghĩa là bạn có thể tránh nếu() kiểm tra. Tôi chỉ có nghĩa là khẳng định() là một cách để đảm bảo devs đã được thông báo mạnh mẽ có một vấn đề. –

1

Các xác nhận chỉ nhằm mục đích kiểm soát chất lượng. Việc xóa chúng không được thay đổi hành vi của chương trình của bạn (tức là chương trình của bạn không được dựa vào các xác nhận để xử lý bất kỳ điều gì). Sử dụng ngoại lệ nếu có điều gì đó không xảy ra nhưng có thể xảy ra trong những trường hợp xấu - ví dụ: mất kết nối mạng. Sử dụng giá trị trả lại để cho biết thành công khi thất bại cũng là một tùy chọn.

0

Tôi sẽ sử dụng khẳng định bất cứ khi nào một cái gì đó giống như một hợp đồng bị hỏng. Tôi có ý nghĩa gì bởi điều này: trong toán học, phân chia bằng 0 không được xác định. Vì vậy, hợp đồng với chức năng phân chia bị hỏng. Thông tin thêm về hợp đồng xem ngôn ngữ progromming Eiffel.

Trong một số trường hợp, tôi sẽ triển khai hàm thứ hai có tham số bổ sung với giá trị mặc định và xử lý ngoại lệ, như StrinToIntegerDef (chuỗi, mặc định), trả về mặc định khi chuỗi không chuyển thành Số nguyên.

Trả lại lỗi có thể được thực hiện trong trường hợp thực hiện chương trình bình thường không bị đe dọa.

Tôi muốn ngoại lệ có ý nghĩa, ít nhất là biểu mẫu xác nhận (điều kiện, thông báo), nếu ngôn ngữ cho phép điều đó.

Ngoài ra, nếu có một số khả năng không thành công, hãy trả về một số giá trị enum thay vì sai.

0

Sử dụng các xác nhận để ủy quyền cho hàm preconditions (các điều kiện phải đúng nếu chức năng có bất kỳ ý nghĩa nào).

+0

Cũng bất biến và (ở cuối hàm) postconditions. – Richard

2

của bạn "return false" cũng được gọi là một GuardClause - như được giải thích bởi Ward Cunningham:

... [G] uards cũng tương tự như khẳng định ở chỗ cả hai bảo vệ tiếp theo đang từ các trường hợp đặc biệt.Các vệ sĩ khác nhau từ các xác nhận rằng họ thực hiện một khoản đóng góp hữu hình vào logic của phương pháp và do đó không thể an toàn được bị bỏ qua như một phần của tối ưu hóa. Tôi đã mượn người bảo vệ hạn từ EwDijkstra khi đặt tên mẫu này.

Nếu điều khoản bảo vệ của bạn có bất kỳ phức tạp nào thì việc đóng gói bằng cách sử dụng BouncerPattern là rất hữu ích.

Như phường chỉ ra, bạn nên sử dụng các xác nhận khi mã có thể được bỏ qua an toàn. Nếu bạn có từ khóa assert bằng ngôn ngữ của mình, trình biên dịch sẽ thường tách xác nhận khỏi mã sản xuất.

Hôm nay, chúng tôi nhận thấy rằng trong hầu hết các trường hợp, không nên đặt xác nhận vào mã của bạn. Chia tách mối quan tâm cổ điển. Phân tách xác nhận từ mã và đóng gói chúng trong một thử nghiệm đơn vị. Điều đó giúp loại bỏ sự phức tạp của việc biên dịch lại mã của bạn mà không có các xác nhận được phân phối (bạn sẽ không phân phối các thử nghiệm của mình ...) và cũng cung cấp cho bạn một bộ kiểm thử có thể chạy liên tục để thu hồi lại và chuyển đổi cấu trúc lại.

Các câu trả lời khác đã đề cập Thiết kế theo hợp đồng, những yếu tố này hoàn toàn nằm ngoài mã của bạn và vào điều kiện tiên quyết, điều kiện và bất biến được thực thi xung quanh mã được đề cập. Nếu bạn làm điều này thường xuyên, bạn có thể xem xét xem xét một khung Design by Contract cho ngôn ngữ của bạn.

Các vấn đề liên quan