18

Kể từ khi Microsoft giới thiệu các khối ứng dụng, tôi đã gặp phải những người sử dụng Exception Handling Application Block. Gần đây tôi đã có một cái nhìn gần hơn bản thân mình và sẽ tóm tắt các chức năng cơ bản như sau (bỏ qua khối sau nếu bạn đã biết nó làm gì):Khối xử lý ngoại lệ của Microsoft - Đây có phải là một ví dụ hoàn hảo cho việc lạm dụng không?

Khối ứng dụng xử lý ngoại lệ nhằm tập trung và cấu hình đầy đủ tập tin cấu hình như sau key exception handling tasks:

  • Logging một ngoại lệ
  • Thay thế một ngoại lệ
  • Bọc một ngoại lệ
  • Propa gating một ngoại lệ
  • , vv

Thư viện nào đó bằng cách bạn sửa đổi các khối catch của bạn như sau:

try 
{ 
    // Run code. 
} 
catch(DataAccessException ex) 
{ 
    bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy"); 
    if (rethrow) 
    { 
     throw; 
    } 
} 

Dựa trên những gì được quy định trong app.config cho tên chính sách (see here for docs), HandleException sẽ hoặc là ...

  • ném một ngoại lệ hoàn toàn mới (thay thế ngoại trừ gốc)
  • bao gồm ngoại lệ ban đầu trong một trường hợp mới và ném rằng
  • nuốt ngoại lệ (tức là không làm gì cả)
  • có bạn rethrow ngoại lệ ban đầu

Ngoài ra bạn cũng có thể cấu hình nó để làm công cụ hơn trước (ví dụ đăng nhập trừ).

Bây giờ đây là vấn đề của tôi: Tôi hoàn toàn không thấy làm thế nào nó có thể có lợi để làm cho nó cấu hình cho dù một ngoại lệ được thay thế, bọc, nuốt hoặc rethrown. Theo kinh nghiệm của tôi, quyết định này phải được thực hiện tại thời điểm bạn viết mã vì bạn thường sẽ phải thay đổi mã xung quanh hoặc gọi khi bạn thay đổi hành vi xử lý ngoại lệ. Ví dụ, mã của bạn có thể sẽ bắt đầu hoạt động không chính xác khi bạn cấu hình lại sao cho một ngoại lệ cụ thể được ném vào một điểm cụ thể bây giờ bị nuốt thay vì bị rethrown (có thể có mã sau khối catch không được thực thi khi ngoại lệ xảy ra). Điều tương tự cũng xảy ra đối với tất cả các thay đổi có thể có khác trong xử lý ngoại lệ (ví dụ: thay thế -> rethrow, swallow -> wrap).

Vì vậy, với tôi dòng dưới cùng là khối xử lý ngoại lệ giải quyết các vấn đề thực sự không tồn tại trong thực tế. Việc ghi nhật ký ngoại lệ và bit thông báo là tốt, nhưng không phải tất cả những thứ khác chỉ là một ví dụ hoàn hảo cho việc overengineering?

+0

Câu hỏi hay. +1. Cũng thêm đối số cho "ngoại lệ loại bỏ sắp xếp thứ tự" trong http://stackoverflow.com/questions/438073#438230. Bạn có thể kiểm tra xem nó? – VonC

Trả lời

12

Nếu bạn sử dụng ngoại lệ cho luồng điều khiển, thì bạn sẽ muốn tránh xa việc xử lý ngoại lệ dựa trên chính sách.

Nhưng trong trường hợp ngoại lệ bạn muốn coi là không thể khôi phục (tác vụ nền không thành công, ổ cắm đã bị ngắt kết nối, tệp đã bị xóa, v.v.), bạn có thể có ngoại lệ dựa trên chính sách có thể định cấu hình xử lý. Ví dụ, nếu bạn đang phát triển một API, bạn có thể muốn có mọi chức năng trong API của bạn chỉ ném ngoại lệ tiêu chuẩn (ArgumentException, v.v.), cũng như ngoại lệ riêng cho thư viện của bạn trong trường hợp của một ngoại lệ không chuẩn bên trong (ví dụ: MyLibraryException). Trong trường hợp này, tất cả những vấn đề đó là một cái gì đó không hoạt động chính xác. Bạn không chọn ra ngoại lệ và tìm ra điều gì đã xảy ra. Bạn chỉ đơn giản là thừa nhận thực tế rằng một số điều đã xảy ra và bạn phải thực hiện một số điều ngay bây giờ.

Điều đó một số điều nên được định cấu hình, vì nó không thực sự quan trọng bạn làm gì. Hiển thị một Hộp Thông báo cho người dùng? Phương thức hay phi phương thức? Ghi ngoại lệ? Bạn muốn đăng nhập ngoại lệ như thế nào? Gọi dịch vụ web đăng nhập? Nối vào tệp nhật ký? Viết vào Nhật ký sự kiện Windows? Chèn một mục vào cơ sở dữ liệu? Chèn một mục vào hai cơ sở dữ liệu? Nó không thực sự quan trọng đối với phần còn lại của ứng dụng của bạn. Việc lựa chọn cách xử lý ngoại lệ hoàn toàn trực giao với phần còn lại của ứng dụng.

(Là một sang một bên, đây không phải là tôi sẽ tiếp cận như thế nào cấu hình dựa trên chính sách ngoại lệ xử lý. Tôi sẽ có xu hướng nhiều hơn đối với một phong cách AOP, chẳng hạn như đăng ký một đánh chặn ngoại lệ-logger trong container.)

+0

Tôi đồng ý rằng bạn có thể muốn định cấu hình những gì sẽ xảy ra (thông báo cho người dùng, ngoại lệ đăng nhập, gửi email để hỗ trợ, v.v.) trước khi ứng dụng của bạn ngừng hoạt động. Bạn dường như đề cập đến tất cả các phần còn lại (nuốt, rethrow, vv) với "kiểm soát dòng chảy", phải không? –

+0

Không nhất thiết - nó phụ thuộc vào phần mềm. Nếu bạn đang xử lý các trường hợp ngoại lệ là có thể phục hồi, thì bạn đang coi chúng là luồng kiểm soát. Nếu bạn coi chúng là không thể phục hồi, thì bạn có thể quan tâm đến khối ứng dụng này. – yfeldblum

+0

Việc xử lý một ngoại lệ là có thể phục hồi sẽ là một cái gì đó gửi một câu lệnh Update tới SQL Server nếu một câu lệnh Insert tương ứng thất bại. Đó là luồng điều khiển. – yfeldblum

1

Rất đơn giản: nếu bạn muốn xử lý ngoại lệ khác nhau trong mã phát hành của bạn hơn trong mã gỡ lỗi, thì nó sẽ hữu ích.

+0

Bạn có ví dụ thực tế về điều đó không? Bạn có rethrow một ngoại lệ cụ thể trong chế độ gỡ lỗi, nhưng nuốt nó trong phát hành? –

+0

Tôi tiếp tục tìm kiếm các ví dụ thực tế này để chứng minh tính hữu ích của nó, nhưng không thành công cho đến nay. –

0

Theo ý kiến ​​của tôi, một giá trị thực của việc sử dụng khối Xử lý ngoại lệ bắt đầu bằng một dòng mã trong khối catch của bạn:

bool rethrow = ExceptionPolicy.HandleException (ex, "Data Access Policy");

Một dòng mã - bạn có thể nhận được đơn giản như thế nào? Đằng sau một dòng mã, chính sách, vì nó được cấu hình, làm cho việc gán/cập nhật cho một chính sách được thực hiện dễ dàng, tất cả mà không cần phải biên dịch lại mã nguồn.

Như đã đề cập, chính sách ngoại lệ có thể thực sự thực hiện nhiều hành động - bất kỳ điều gì được xác định trong chính sách của bạn. Ẩn tính phức tạp đằng sau một dòng mã như được hiển thị bên trong khối catch, là nơi tôi thấy giá trị thực.

Tôi sẽ nói phức tạp, nhưng không quá tải. Vì vậy, suy nghĩ của tôi là cổ tức lớn sẽ được nhìn thấy trong quá trình bảo trì khi bạn cần thay đổi cách bạn xử lý/ghi nhật ký ngoại lệ bằng cách linh hoạt thay đổi cấu hình dễ dàng và vẫn có cùng một dòng mã nguồn.

+1

Ok, nhưng bạn đã từng thấy sự cần thiết chỉ ** chỉ ** thay đổi tuyên truyền ngoại lệ (ngoại lệ đặc biệt này đã được trả lại trong quá khứ, chúng ta hãy bọc nó trong một ngoại lệ khác và ném nó trong tương lai) và để lại tất cả các mã xung quanh không thay đổi ? –

5

Tôi gặp sự cố này khi tôi phát triển các hàm không có trạng thái có thể phục hồi. Tôi tin rằng việc xử lý ngoại lệ theo hướng chính sách này thực sự hữu ích và đảm bảo rằng tất cả các nhà phát triển khác là một phần của dự án này thực sự tuân thủ tiêu chuẩn cho các ngoại lệ không thể khôi phục.

Tôi đồng ý với các áp phích ở trên, bạn có thể muốn tránh xa các trường hợp ngoại lệ dựa trên chính sách nếu bạn đang sử dụng chúng cho luồng kiểm soát.

3

Tôi không nghĩ điều này hoàn toàn là kỹ thuật. trong thực tế. thực tế là các ngoại lệ có thể đi qua một trình xử lý trung tâm là một điều tốt trong công việc của tôi. tôi đã có các nhà phát triển, những người sẽ ăn tất cả các ngoại lệ - được xử lý hay không để nó không bị bong bóng lên đầu và đặt một cái gì đó đáng báo động trước người dùng cuối hoặc làm hỏng một dịch vụ/daemon khi không bị bắt.

giờ đây với chính sách chúng tôi có thể bắt đầu ghi nhật ký bất cứ lúc nào mà không phải khởi động lại hoặc không cần thiết phải rải logic đăng nhập trong suốt ứng dụng. bây giờ chúng ta có thể xem ngoại lệ và những thứ tương tự mà không cần dùng ứng dụng ngoại tuyến.

lập trình thông minh nếu bạn hỏi tôi ...

+0

Về các nhà phát triển ăn ngoại lệ: Sẽ không tốt hơn nếu bạn kiểm tra mã của họ bằng các công cụ phân tích mã (ví dụ: FxCop) để đảm bảo rằng họ không chỉ nuốt tất cả mọi thứ? –

+1

Có. Có nó sẽ, nhưng ngay cả khi phát hiện - nó khó để biện minh cho một retasking/kiểm tra lại những thứ đó đã có trong sản xuất. Không phải là chúng tôi không cố gắng nắm bắt/ngăn chặn nhưng không có cơ sở mã được miễn dịch từ một người quản lý trong một vội vàng và một nhà phát triển sẵn sàng để chứa chúng. – MikeJ

4

tôi phải đồng ý với tuyên bố rằng "khối xử lý ngoại lệ giải quyết vấn đề mà thực sự không tồn tại trong thực tế." Tôi đã sử dụng các khối kể từ khi phát hành và tôi hiếm khi cảm thấy như tôi thực sự đạt được nhiều bằng cách sử dụng nó. Vâng, có lẽ hơi đau đầu. :)

Trước khi bắt đầu, tôi sẽ thừa nhận rằng tôi thích chức năng Exception Shielding at WCF Service Boundaries. Tuy nhiên, điều đó đã được bổ sung khá gần đây, không liên quan đến các thuộc tính và cấu hình chỉ mã hóa, và không phải là cách khối thường được bán. Đây là cách Microsoft cho thấy nó ở http://msdn.microsoft.com/en-us/library/cc309250.aspx

alt text http://i.msdn.microsoft.com/Cc309250.05-CrossLayer(en-us,MSDN.10).gif

Để đôi mắt của tôi ở trên là kiểm soát dòng chảy.

try 
{ 
    // Run code. 
} 
catch(DataAccessException ex) 
{ 
    bool rethrow = ExceptionPolicy.HandleException(ex, "Data Access Policy"); 
    if (rethrow) 
    { 
     throw; 
    } 
} 

Khi bạn kết hợp khía cạnh điều khiển luồng với mã ở trên chắc chắn bạn không phải là making wrong code look wrong. (Đừng bận tâm rằng cấu trúc if (rethrow) không cung cấp nhiều trừu tượng.) Điều này có thể làm cho việc bảo trì khó khăn hơn cho các nhà phát triển không quen thuộc với các định nghĩa chính sách. Nếu postHandlingAction trong tệp cấu hình bị thay đổi (có thể nó sẽ xảy ra tại một số điểm), bạn có thể sẽ thấy ứng dụng hoạt động theo những cách bất ngờ chưa bao giờ được thử nghiệm.

Có lẽ tôi sẽ không thấy nó có thể bị phản đối nếu khối không xử lý điều khiển luồng nhưng chỉ cho phép bạn xử lý chuỗi với nhau.

Nhưng có lẽ không. Tôi thực sự không nhớ là đã từng được yêu cầu:

  • thêm một chức năng mới khi xử lý ngoại lệ (ví dụ: ngoài ghi nhật ký sự kiện cũng gửi email). một mình nếu bạn đã tự đăng nhập ngoại lệ. :))
  • thay đổi hành vi xử lý ngoại lệ (nuốt, quay lại hoặc ném mới) trên toàn bộ "chính sách".

Tôi không nói rằng điều đó không xảy ra (tôi chắc rằng ai đó có câu chuyện!); Tôi chỉ cảm thấy rằng Khối ứng dụng xử lý ngoại lệ làm cho các chương trình khó hiểu và duy trì và điều này thường vượt trội hơn so với chức năng do khối cung cấp.