2009-12-03 27 views
6

Có tiêu chuẩn thực hành hay tiêu chuẩn công nghiệp nào tốt nhất cho việc ném ngoại lệ từ API của bộ công cụ không?Xác định ngoại lệ có thể được ném từ bộ công cụ API

Phương pháp đối diện người dùng có bắt được và kết thúc Exception ở một số loại CustomException để người dùng chỉ phải lo lắng về việc CustomException sắp ra khỏi API không?

Hoặc là quy ước để chỉ cho phép những bong bóng đó lên?

Chúng tôi quan tâm đến việc có thể ghi lại tất cả các ngoại lệ có thể mà các phương pháp API của chúng tôi có thể ném. (Ví dụ: nếu phương thức API của chúng tôi gọi số Stream.Write() có 4 hoặc 5 ngoại lệ, chúng tôi sẽ phải ghi lại tất cả những trường hợp ngoại trừ các ngoại lệ khác mà các phương thức được gọi khác có thể ném.)

Chúng tôi đang nghĩ đến việc làm này:

public void customerFacingApiMethod(){ 
    try { 
     //api functionality goes here 
    } catch (Exception e) { 
     throw new CustomException(e); 
    } 
} 

Trả lời

13

Theo ý kiến ​​của tôi, API chỉ ném một loại ngoại lệ là ý tưởng tồi. Một trong những điều tốt với các ngoại lệ khác nhau là bạn có thể chọn bắt các loại ngoại lệ khác nhau và xử lý chúng khác nhau. Đưa các ngoại lệ vào một loại ngoại lệ duy nhất sẽ loại bỏ cơ sở đó.

Sử dụng các loại ngoại lệ do khung làm việc cung cấp khi thích hợp và tạo loại ngoại lệ tùy chỉnh của riêng bạn cho các tình huống cụ thể khi thích hợp. Và trên tất cả, hãy đảm bảo tài liệu cho từng phương pháp mà ngoại lệ mà họ có thể ném.

+1

+1 để không ẩn chi tiết ngoại lệ nội bộ – Oded

+0

Về nguyên tắc, chúng tôi đồng ý. Nhưng nếu một trong những cuộc gọi chúng tôi đang thực hiện thay đổi một ngoại lệ nó ném, bây giờ tài liệu của chúng tôi là không đồng bộ. Hoặc nếu tài liệu của họ là không chính xác và có một ngoại lệ ném mà không phải là tài liệu. –

+3

nếu điều gì sẽ xảy ra nếu như thế nào. Bạn có thể làm gì nếu bản thân bạn chết, quan điểm là bạn đang phá hủy tính năng ngoại lệ lớn nhất, đó là chúng được nhập. – Fred

1

Tôi không thích nó. Nếu bạn bọc tất cả các ngoại lệ vào một CustomException sẽ rất khó để nắm bắt các ngoại lệ cụ thể mà không cần tìm kiếm bên trong đối tượng cho InnerExcpetion (có thể là nhiều cấp độ sâu nếu API của bạn cũng sử dụng các API khác làm điều tương tự). Nếu có một OutOfMemoryException, tôi muốn biết rằng không cần phải tìm kiếm nó.

1

Không sử dụng cùng một ngoại lệ cho tất cả.

Bạn cần các loại ngoại lệ khác nhau để có thể tách riêng một trường hợp khỏi một trường hợp khác. Đối với bất cứ điều gì mà bạn muốn cho nó chảy lên cho đến khi một khối xử lý ngoại lệ chung bắt nó sẽ có vẻ k, nhưng bạn đang ngăn chặn bất kỳ phục hồi mã khác - các hành động phụ hoạt động trên các trường hợp cụ thể.

Bạn có thể bao gồm một tập hợp các ngoại lệ, nếu những trường hợp đó phù hợp với một tình huống cụ thể có thể được xử lý bằng mã gọi. Đừng quên rằng một số ngoại lệ khuôn khổ đã giao tiếp tình hình tốt.

1

Điều Fredrik Mork nói là rất đúng. Tôi cũng muốn thêm vào đó bạn có thể dễ dàng ghi lại các ngoại lệ được đưa ra với các nhận xét xml (và GhostDoc).

Vì vậy, người dùng API có thể tra cứu trong tài liệu để xem những ngoại lệ nào có thể được ném. Tuy nhiên, có một nhược điểm.

Nếu bạn có một callstack sâu bên trong API của bạn và đặc biệt là nếu mức độ phức tạp cyclomatic trở thành cao (tức là num chi nhánh có thể) bạn không thể khôi phục lại tất cả các trường hợp ngoại lệ có thể có thể được ném (có lẽ do thời gian chạy?)

Vì vậy, tôi sẽ khuyên bạn nên chỉ ném nếu một cái gì đó nếu phục hồi là không thể và chỉ ném trong lớp trên của API của bạn, tức là không sâu hơn 2 sâu. Và nắm bắt tất cả các ngoại lệ được ném sâu hơn trong callstack của bạn và trả lại chúng như InnerException hoặc một cái gì đó như thế.

3

Khi ném ngoại lệ, hãy đảm bảo rằng ngoại lệ hướng đến người dùng có liên quan đến những gì người dùng thực sự đã làm sai liên quan đến bộ công cụ của bạn. Điều đó có nghĩa là bắt hoặc hợp nhất các ngoại lệ hệ thống tệp khác nhau thành một ngoại lệ duy nhất nhưng bạn không bao giờ nên bắt ngoại lệ và ném một ngoại lệ mới - điều đó không thực sự nói cho người dùng bộ công cụ biết họ đã làm gì sai.

3

Bạn nên làm theo cùng các khái niệm như Khuôn khổ .NET. Người dùng của bạn đã sử dụng khung làm việc, vì vậy họ biết cách hoạt động và mong đợi hành vi nhất định.

  • Ném một ngoại lệ -derived ArgumentException nếu một cuộc tranh cãi từ các khách hàng là không hợp lệ (sử dụng ArgumentNullException, ArgumentOutOfRangeException vv nếu thích hợp).
  • Ném ngoại lệ IOException cho các lỗi IO.

Etc ...

Trong tài liệu của bạn, nêu rõ điều kiện tiên quyết cho API công cộng của bạn và nêu các trường hợp ngoại lệ sẽ được ném ra khi họ thất bại (như MSDN không).

1

Có hai loại trường hợp ngoại lệ để xem xét (bỏ qua StackOverflowException, vv, mà bạn không thể làm bất cứ điều gì về anyway):

  1. Những người được gây ra bởi các vấn đề bên ngoài (như file IO), trong đó phải được xử lý.
  2. Những thứ đó luôn có thể tránh được với đầu vào được xác thực hợp lệ.

Điều này thường có ý nghĩa đối với trường hợp ngoại lệ loại IO được chuyển lên ngăn xếp cuộc gọi chưa sửa đổi, vì không có bất kỳ điều gì bạn thực sự có thể thực hiện. Ngoại lệ cho điều này sẽ được dự đoán lỗi mà bạn có thể làm retries, hoặc yêu cầu người dùng phải làm gì, nếu API của bạn hoạt động ở cấp độ GUI (mà sẽ là khá bất thường).

Chỉ cần đảm bảo ghi lại các ngoại lệ của loại phương pháp API này có thể ném.

Loại thứ hai (ngoại lệ luôn có thể được ngăn chặn), những ngoại lệ này có thể do API của bạn tạo ra vào đầu vào kém, nhưng không bao giờ được chuyển lên ngăn xếp cuộc gọi từ cấp thấp hơn. Đầu vào cho bất cứ điều gì bạn gọi nên được xác nhận để các lỗi này không xảy ra, và nếu vì một lý do nào đó, chúng có thể xảy ra, thì những trường hợp ngoại lệ này sẽ được bao bọc. Nếu không, mã sử dụng API của bạn sẽ phải đối phó với các ngoại lệ ở mức trừu tượng sai.

Và một lần nữa, hãy nhớ ghi lại loại đầu vào nào sẽ không tạo ngoại lệ và loại ngoại lệ nào sẽ xảy ra nếu các quy tắc này bị hỏng.

Trong mọi trường hợp, hãy ném ngoại lệ có ý nghĩa với người dùng API của bạn, không phải người lập trình API.

1

Sự cố khi bắt System.Exception trong trường hợp chung là bằng cách làm như vậy, bạn đang nói "Tôi không biết tại sao điều này không thành công, và tôi không thể tiếp tục ! "

Điều đó hiếm khi, nếu có, đúng.

Bao bọc tất cả các ngoại lệ trong một loại ngoại lệ tùy chỉnh duy nhất có nghĩa là người tiêu dùng của bạn sẽ chỉ bắt được loại đó - sau đó sẽ tương đương về mặt đạo đức khi bắt System.Exception. Trong khi bạn có thể đáp ứng một số quy tắc của chính sách/FXCop bằng cách thực hiện điều đó, bạn vẫn thực sự chỉ bắt được System.Exception.

Đối với chính sách ngoại lệ của bạn, tôi bắt đầu bằng cách yêu cầu điều này: "Nếu tôi không biết API này thực sự được nói đến, loại ngoại lệ nào tôi sẽ quay lại?" Và hãy nhớ rằng một phương pháp là một yêu cầu đối tượng để làm điều gì đó, và một ngoại lệ là cách của đối tượng cho bạn biết rằng nó không thể, và lý do tại sao.

0

Nếu bạn tạo một loại ngoại lệ duy nhất để sử dụng trong suốt API của mình, ý nghĩa của nó sẽ mơ hồ đối với các ứng dụng khách gặp phải loại ngoại lệ đó. Thay vào đó, hãy cân nhắc tạo một phân cấp lớp học ngoại lệ ngoại lệ cho API của bạn.

Để làm như vậy, lần đầu tiên xác định một bản tóm tắt kiểu cơ sở ngoại lệ:

CustomException 

... và sau đó lấy được các loại ngoại lệ cụ thể hơn từ nó. Ví dụ:

CustomFooException 
CustomBarException 
CustomFizException 
CustomFuzException 

Loại cơ sở trừu tượng CustomException sẽ không bao giờ được ném trực tiếp từ API của bạn. Tuy nhiên, một khách hàng của API của bạn có thể nắm bắt loại ngoại lệ cơ sở CustomException nếu nó không quan tâm đến ngoại lệ có nguồn gốc cụ thể nào được ném từ API của bạn.

Để biết thêm về ý tưởng phát triển một hệ thống phân cấp lớp ngoại lệ, xem this answer và các câu trả lời cho câu hỏi này: Why create custom exceptions in .NET?

Xem thêm this answer trong đó giới thiệu ý tưởng về làm cho lớp cơ sở trừu tượng của hệ thống phân cấp ngoại trừ của bạn.

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