Những ngoại lệ nào nên được ném cho các tham số không hợp lệ hoặc không mong muốn trong .NET?


163

Những loại ngoại lệ nào nên được ném cho các tham số không hợp lệ hoặc không mong muốn trong .NET? Khi nào tôi sẽ chọn cái này thay vì cái khác?

Theo sát:

Bạn sẽ sử dụng ngoại lệ nào nếu bạn có một hàm mong đợi một số nguyên tương ứng với một tháng và bạn đã vượt qua trong '42'? Điều này sẽ rơi vào danh mục "ngoài phạm vi" mặc dù nó không phải là một bộ sưu tập?

Câu trả lời:


249

Tôi thích sử dụng: ArgumentException, ArgumentNullException, và ArgumentOutOfRangeException.

Cũng có những lựa chọn khác, nó không tập trung quá nhiều vào chính đối số, mà là đánh giá toàn bộ cuộc gọi:

  • InvalidOperationException- Đối số có thể ổn, nhưng không ở trạng thái hiện tại của đối tượng. Tín dụng vào STW (trước đây là Yoooder). Bình chọn câu trả lời của anh ấy là tốt.
  • NotSupportedException- Các đối số được truyền vào là hợp lệ, nhưng chỉ không được hỗ trợ trong việc thực hiện này. Hãy tưởng tượng một máy khách FTP và bạn truyền một lệnh trong đó máy khách không hỗ trợ.

Bí quyết là đưa ra ngoại lệ thể hiện rõ nhất lý do tại sao phương thức không thể được gọi là như vậy. Tốt nhất, ngoại lệ nên được chi tiết về những gì đã sai, tại sao nó sai và cách khắc phục.

Tôi thích khi thông báo lỗi trỏ đến trợ giúp, tài liệu hoặc các tài nguyên khác. Ví dụ: Microsoft đã thực hiện bước đầu tiên tốt với các bài viết KB của họ, ví dụ: Tại sao tôi nhận được thông báo lỗi "Thao tác bị hủy bỏ" khi tôi truy cập trang Web trong Internet Explorer? . Khi bạn gặp lỗi, họ chỉ cho bạn bài viết KB trong thông báo lỗi. Điều họ làm không tốt là họ không nói với bạn, tại sao cụ thể là nó thất bại.

Cảm ơn STW (ex Yoooder) một lần nữa cho các bình luận.


Đáp lại sự theo dõi của bạn, tôi sẽ ném một cái ArgumentOutOfRangeException. Nhìn vào những gì MSDN nói về ngoại lệ này:

ArgumentOutOfRangeExceptionđược ném khi một phương thức được gọi và ít nhất một trong các đối số được truyền cho phương thức đó không phải là tham chiếu null ( Nothingtrong Visual Basic) và không chứa giá trị hợp lệ.

Vì vậy, trong trường hợp này, bạn đang truyền một giá trị, nhưng đó không phải là giá trị hợp lệ, vì phạm vi của bạn là 1 V1212. Tuy nhiên, cách bạn ghi lại nó làm cho nó rõ ràng, những gì API của bạn ném. Bởi vì mặc dù tôi có thể nói ArgumentOutOfRangeException, một nhà phát triển khác có thể nói ArgumentException. Làm cho nó dễ dàng và tài liệu hành vi.


Psst! Tôi đồng ý rằng bạn đã trả lời chính xác câu hỏi cụ thể của anh ấy, nhưng hãy xem câu trả lời của tôi dưới đây để giúp làm tròn các thông số mã hóa và xác thực phòng thủ ;-D
STW

+1 nhưng ghi lại ngoại lệ nào được ném và tại sao quan trọng hơn là chọn 'đúng'.
pipTheGeek

@pipTheGeek - Tôi nghĩ đó thực sự là một điểm cần thiết. Mặc dù tài liệu là rất quan trọng, nó cũng hy vọng nhà phát triển tiêu thụ sẽ chủ động hoặc phòng thủ và thực sự đọc tài liệu một cách chi tiết. Tôi sẽ chọn một lỗi thân thiện / mô tả đối với tài liệu tốt vì người dùng cuối có cơ hội nhìn thấy một trong số họ chứ không phải người khác; có một cơ hội tốt hơn để người dùng cuối giao tiếp một lỗi mô tả cho một lập trình viên nghèo hơn là một lập trình viên nghèo đọc các tài liệu đầy đủ
STW

4
Lưu ý, nếu bạn bắt được ArgumentException, nó cũng sẽ bắt được ArgumentOutOfRange.
Steven Evers

Làm thế nào về FormatException: Ngoại lệ được ném khi định dạng của một đối số không hợp lệ hoặc khi một chuỗi định dạng tổng hợp không được hình thành tốt.
Anthony

44

Tôi đã bình chọn cho câu trả lời của Josh , nhưng muốn thêm một người nữa vào danh sách:

Nên ném System.InvalidOperationException nếu đối số hợp lệ, nhưng đối tượng ở trạng thái không nên sử dụng đối số.

Cập nhật lấy từ MSDN:

UnlimitedOperationException được sử dụng trong các trường hợp khi không thể gọi một phương thức được gây ra bởi các lý do khác với các đối số không hợp lệ.

Giả sử đối tượng của bạn có phương thức PerformanceAction (hành động enmSomeAction), enmSomeActions hợp lệ là Mở và Đóng. Nếu bạn gọi PerformanceAction (enmSomeAction.Open) hai lần liên tiếp thì cuộc gọi thứ hai sẽ ném UnlimitedOperationException (vì lệnh này là hợp lệ, nhưng không phải cho trạng thái hiện tại của điều khiển)

Vì bạn đã làm đúng bằng cách lập trình phòng thủ, tôi có một ngoại lệ khác phải kể đến là ObjectDisposedException. Nếu đối tượng của bạn triển khai IDis Dùng thì bạn phải luôn có một biến lớp theo dõi trạng thái xử lý; nếu đối tượng của bạn đã được xử lý và một phương thức được gọi trên đó, bạn nên nâng ObjectDisposedException:

public void SomeMethod()
{
    If (m_Disposed) {
          throw new ObjectDisposedException("Object has been disposed")
     }
    // ... Normal execution code
}

Cập nhật: Để trả lời theo dõi của bạn: Đó là một tình huống mơ hồ và được làm phức tạp hơn một chút bởi một loại dữ liệu chung (không phải theo nghĩa của Generics .NET) được sử dụng để biểu diễn một tập hợp dữ liệu cụ thể; một enum hoặc đối tượng được gõ mạnh khác sẽ phù hợp hơn với lý tưởng - nhưng chúng ta không phải lúc nào cũng có sự kiểm soát đó.

Cá nhân tôi sẽ nghiêng về phía ArgumentOutOfRangeException và cung cấp một thông báo cho biết các giá trị hợp lệ là 1-12. Lý do của tôi là khi bạn nói về tháng, giả sử tất cả các biểu diễn số nguyên của tháng là hợp lệ, thì bạn đang mong đợi một giá trị trong phạm vi 1-12. Nếu chỉ một số tháng nhất định (như tháng có 31 ngày) là hợp lệ thì bạn sẽ không phải đối phó với Phạm vi mỗi lần và tôi sẽ đưa ra một ArgumentException chung chỉ ra các giá trị hợp lệ và tôi cũng sẽ ghi lại chúng trong các nhận xét của phương thức.


1
Điểm tốt. Điều này có thể giải thích sự khác biệt giữa đầu vào không hợp lệ và không được phát hiện. +1
Daniel Brückner

Psst, tôi đồng ý với bạn là sẽ không đánh cắp sấm sét của bạn. Nhưng vì bạn đã chỉ ra, tôi đã cập nhật câu trả lời của mình
JoshBerke

38

Tùy thuộc vào giá trị thực tế và ngoại lệ nào phù hợp nhất:

Nếu điều này không đủ chính xác, chỉ cần lấy lớp ngoại lệ của riêng bạn từ đó ArgumentException.

Câu trả lời của Yoooder đã khai sáng cho tôi. Một đầu vào không hợp lệ nếu nó không hợp lệ bất cứ lúc nào, trong khi đầu vào là bất ngờ nếu nó không hợp lệ cho trạng thái hiện tại của hệ thống. Vì vậy, trong trường hợp sau, an InvalidOperationExceptionlà một lựa chọn hợp lý.


6
Lấy từ trang của MSDN trên UnlimitedOperationException: "UnlimitedOperationException được sử dụng trong các trường hợp khi không thể gọi một phương thức được gây ra bởi các lý do khác với các đối số không hợp lệ."
STW


3

Đối số ngoại lệ :

ArgumentException được ném khi một phương thức được gọi và ít nhất một trong các đối số được truyền không đáp ứng đặc tả tham số của phương thức được gọi. Tất cả các phiên bản của ArgumentException sẽ mang một thông báo lỗi có ý nghĩa mô tả đối số không hợp lệ, cũng như phạm vi giá trị dự kiến ​​cho đối số.

Một vài lớp con cũng tồn tại cho các loại vô hình cụ thể. Liên kết có tóm tắt của các kiểu con và khi nào chúng nên áp dụng.


1

Trả lời ngắn gọn:
Không

Câu trả lời dài hơn:
sử dụng Đối số * Ngoại lệ (ngoại trừ trong thư viện là sản phẩm trên đó, chẳng hạn như thư viện thành phần) là một mùi. Các ngoại lệ là để xử lý tình huống đặc biệt, không phải lỗi và không phải là thiếu hụt của người dùng (tức là người tiêu dùng API).

Câu trả lời dài nhất:
Ném ngoại lệ cho các đối số không hợp lệ là thô lỗ, trừ khi bạn viết thư viện.
Tôi thích sử dụng các xác nhận, vì hai (hoặc nhiều) lý do:

  • Các xác nhận không cần phải được kiểm tra, trong khi các xác nhận ném thì có, và kiểm tra đối với ArgumentNullException trông thật lố bịch (hãy thử).
  • Các xác nhận truyền đạt tốt hơn mục đích sử dụng của đơn vị và gần với tài liệu thực thi hơn là một đặc tả hành vi lớp.
  • Bạn có thể thay đổi hành vi vi phạm khẳng định. Ví dụ: trong quá trình biên dịch gỡ lỗi, hộp thông báo vẫn ổn, do đó QA của bạn sẽ đánh bạn ngay lập tức (bạn cũng nhận được IDE của mình bị hỏng trên dòng xảy ra), trong khi kiểm tra đơn vị, bạn có thể chỉ ra lỗi xác nhận là lỗi kiểm tra .

Đây là cách xử lý ngoại lệ null trông như thế nào (rõ ràng là mỉa mai):

try {
    library.Method(null);
}
catch (ArgumentNullException e) {
    // retry with real argument this time
    library.Method(realArgument);
}

Các ngoại lệ sẽ được sử dụng khi tình huống được mong đợi nhưng ngoại lệ (những điều xảy ra nằm ngoài tầm kiểm soát của người tiêu dùng, chẳng hạn như lỗi IO). Đối số * Ngoại lệ là một dấu hiệu của lỗi và sẽ (theo ý kiến ​​của tôi) được xử lý bằng các thử nghiệm và được hỗ trợ với Debug.Assert

BTW: Trong trường hợp cụ thể này, bạn có thể đã sử dụng loại Tháng, thay vì int. C # không đạt được khi nói đến loại an toàn (Aspect # rulez!) Nhưng đôi khi bạn có thể ngăn chặn (hoặc bắt kịp thời gian biên dịch) các lỗi đó cùng nhau.

Và vâng, MicroSoft đã sai về điều đó.


6
IMHO, ngoại lệ cũng nên được ném khi phương thức được gọi không thể tiến hành hợp lý. Điều đó bao gồm cả trường hợp khi người gọi đã vượt qua các đối số không có thật. Bạn sẽ làm gì thay thế? Trả về -1?
John Saunders

1
Nếu các đối số không hợp lệ sẽ khiến một hàm bên trong không thành công, thì những ưu và nhược điểm của các đối số kiểm tra tính hợp lệ là gì, so với việc bắt một UnlimitedArgumentException từ hàm bên trong và bọc nó bằng một thông tin nhiều hơn? Cách tiếp cận thứ hai dường như sẽ cải thiện hiệu suất trong trường hợp phổ biến, nhưng tôi không thấy nó được thực hiện nhiều.
supercat

Một tìm kiếm nhanh trên google xung quanh câu hỏi này chỉ ra rằng ném Ngoại lệ chung là cách thực hành tồi tệ nhất. Liên quan đến một khẳng định của đối số, tôi thấy có công trong việc này đối với các dự án cá nhân nhỏ, nhưng không phải trên các ứng dụng doanh nghiệp nơi các đối số không hợp lệ rất có thể là do cấu hình kém hoặc hiểu biết kém về ứng dụng.
Tối đa

0

Có một ArgumentException tiêu chuẩn mà bạn có thể sử dụng hoặc bạn có thể phân lớp và tạo riêng cho mình. Có một số lớp ArgumentException cụ thể:

http://msdn.microsoft.com/en-us/l Library / system.argumentexception (VS.71) .aspx

Bất cứ ai làm việc tốt nhất.


1
Tôi không đồng ý với gần như tất cả các trường hợp; Đối số .NET được cung cấp * Các lớp ngoại lệ được sử dụng rất phổ biến và cung cấp cho bạn khả năng cung cấp đủ thông tin cụ thể để thông báo cho người tiêu dùng về vấn đề này.
STW

Để làm rõ - tôi không đồng ý với gần như tất cả các trường hợp xuất phát từ các lớp Đối số * Ngoại lệ. Sử dụng một trong các Ngoại lệ đối số .NET cộng với thông báo mô tả và rõ ràng cung cấp đủ chi tiết cho ít nhiều mọi tình huống trong đó các đối số không hợp lệ.
STW

đồng ý, nhưng tôi chỉ mô tả các tùy chọn có sẵn. Tôi chắc chắn nên rõ ràng hơn về phương pháp "ưa thích".
Scott M.
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.