2010-06-24 32 views
9

Một trong những thú cưng của tôi với sự kiện nâng cao trong C# là một ngoại lệ trong trình xử lý sự kiện sẽ phá vỡ mã của tôi và có thể ngăn các trình xử lý khác bị gọi một xảy ra để được gọi là đầu tiên; Trong hầu hết các trường hợp, mã của tôi không thể quan tâm nếu mã của ai đó đang lắng nghe các sự kiện của nó bị hỏng.Tăng sự kiện trong C# mà bỏ qua ngoại lệ do người xử lý nêu ra

Tôi tạo ra một phương pháp mở rộng mà bắt ngoại lệ:

public static void Raise(this EventHandler eh, object sender, EventArgs e) 
{ 
    if (eh == null) 
    return; 
    try 
    { 
    eh(sender, e); 
    } 
    catch { } 
} 

Mặc dù điều này không có nghĩa là mã của tôi mang về không phân biệt, phương pháp này không chỉ dừng lại một xử lý sự kiện đầu tiên ném một ngoại lệ và ngăn chặn xử lý thứ hai và tiếp theo là thông báo về sự kiện. Tôi đang xem xét một cách lặp qua GetInvocationList để bao bọc từng trình xử lý sự kiện riêng lẻ trong thử/nắm bắt riêng của nó, nhưng điều này có vẻ không hiệu quả và tôi không chắc chắn cách tốt nhất để làm điều đó, hoặc thậm chí nếu tôi nên làm.

Ngoài ra, tôi thực sự không thoải mái đơn giản là bỏ qua ngoại lệ ở đây (và cả FxCop/Resharper cho vấn đề đó); thực tế điều gì sẽ xảy ra với ngoại lệ trong trường hợp này?

+1

Tôi thường tự hỏi cách tốt nhất để xử lý vấn đề này là gì. – ChaosPandion

+0

Điều này thực sự đặt ra một câu hỏi khác tôi sẽ hỏi riêng; trong câu hỏi này tôi đang mã hóa từ quan điểm của lớp nâng cao sự kiện, nhưng tôi tự hỏi nếu xử lý sự kiện nên được phép ném ngoại lệ ở nơi đầu tiên. http://stackoverflow.com/questions/3114543/should-event-handlers-in-c-ever-raise-exceptions – Flynn1179

Trả lời

2

Nếu bạn làm điều gì đó như thế này thì sao?

public static void Raise(this EventHandler eh, object sender, EventArgs e) 
{ 
    if (eh == null) 
     return; 

    foreach(var handler in eh.GetInvocationList().Cast<EventHandler>()) 
    { 
     try 
     { 
      handler(sender, e); 
     } 
     catch { } 
    } 
} 
+0

Trên thực tế, tôi đã làm 'foreach (xử lý ủy nhiệm trong WeaponChanged.GetInvocationList()) handler (người gửi, e);', nhưng không may, trình xử lý '(người gửi, e)' đưa ra một lỗi trong VS, 'Phương thức, đại biểu hoặc sự kiện được mong đợi 'cho' xử lý '; Tôi đang gãi đầu trên cái đó, rõ ràng là một đại biểu. – Flynn1179

+0

@ Flynn1179 - Ủy quyền của nó tự không thể được gọi trong vấn đề đó. Bạn cần phải cast như bạn thấy trong ví dụ của tôi hoặc gọi các delegate như thế này: 'handler.DynamicInvoke (người gửi, e); ' – ChaosPandion

+0

aah .. Tôi đang bối rối giữa' delegate 'và' Delegate ':) – Flynn1179

3

Bạn chỉ nên bẫy những ngoại lệ đó mà bạn có thể xử lý. Ví dụ: bạn có thể đang truy cập một tệp và không có đủ đặc quyền. Nếu bạn biết điều này có thể xảy ra đôi khi và tất cả những gì cần phải xảy ra là trường hợp được đăng nhập thì bẫy ngoại lệ đó một mình.

Nếu mã của bạn không thể xử lý ngoại lệ thì đừng bẫy nó.

Đó là một trường hợp đặc biệt nên có khả năng các trình xử lý sự kiện khác sẽ không thể "thực hiện công cụ của họ", vì vậy hãy để nó truyền tới mức có thể xử lý an toàn.

3

Nếu trình xử lý sự kiện không bắt được ngoại lệ, tôi không thấy bất kỳ cách nào tốt để bạn có thể xử lý ngoại lệ trong lớp đang ném sự kiện. Bạn không có bất kỳ ngữ cảnh nào để biết những gì mà trình xử lý đang làm. Cách an toàn nhất là để ứng dụng gặp sự cố nghiêm trọng trong trường hợp này, vì bạn không biết tác dụng phụ nào mà trình xử lý sự kiện khác có thể gây ra có thể làm mất ổn định ứng dụng của bạn. Bài học ở đây là các trình xử lý sự kiện phải mạnh mẽ (xử lý các ngoại lệ riêng của chúng), vì các lớp mà các sự kiện cháy sẽ không bao giờ bắt được các ngoại lệ được ném bởi các trình xử lý.

+0

Không nhanh chóng là tuyệt vời khi bạn đang gỡ lỗi, nhưng không quá nhiều khi bạn là người dùng. Tại sao một trình cắm bị lỗi làm hỏng mọi ứng dụng mà nó chạm vào? – Gabe

+0

Nếu bạn có một trình cắm thêm bị lỗi và bạn muốn có một kiến ​​trúc mạnh mẽ thực sự, thì bạn cần tách biệt plugin để nó không thể gây hại cho ứng dụng của bạn. Bạn có thể làm điều này với một AppDomain hoặc một quá trình riêng biệt. Nếu nó không bị cô lập, sau đó bạn không thể đảm bảo nhà nước của bạn đã không bị hỏng và tiếp tục chạy mặc dù một ngoại lệ unhandled là một công thức cho thất bại tồi tệ hơn nhiều xuống dòng. Về cơ bản, chạy không chính xác là tồi tệ hơn không chạy ở tất cả và nếu bạn không thể chắc chắn rằng bạn vẫn có thể chạy một cách chính xác, nó tốt hơn để thất bại. –

+1

@Gabe - Một trình cắm thêm bị lỗi sẽ làm hỏng mọi ứng dụng mà nó chạm vào, bởi vì nó là một trình cắm thêm bị lỗi. Mọi người nên được thực hiện nhận thức được thực tế rằng nó là lỗi, vì vậy nó có thể được cố định hoặc tránh. Việc bảo vệ các trình cắm thêm tệ hại với chi phí có thể có của dữ liệu của người dùng là một chính sách tồi. –

2

Một nguyên tắc đơn giản nhưng quan trọng:

Mỗi khiếm khuyết trong mã nên càng gây chết người càng tốt càng sớm càng càng tốt.

Bằng cách này, các lỗi được tìm thấy và sửa lỗi và phần mềm phát triển mạnh mẽ hơn bao giờ hết. Những gì người khác đang nói là chính xác; không bao giờ bắt được ngoại lệ mà bạn không mong đợi và biết cách xử lý.

+0

Mọi người cứ nói điều này nhưng nó không phải lúc nào cũng đơn giản như vậy. Điều gì xảy ra nếu họ không kiểm soát được ai đăng ký sự kiện? Điều gì sẽ xảy ra nếu bắt buộc quá trình xử lý tiếp tục? – ChaosPandion

+1

@Chaos, trong trường hợp đó, bạn cần cấu trúc các sự kiện theo cách cho phép cô lập. Ví dụ, thiết lập mô hình máy khách/máy chủ với các tiến trình riêng biệt. Bây giờ một khách hàng có thể sụp đổ và máy chủ có thể vui vẻ tiếp tục xử lý, ngay cả khi khách hàng bị lỗi. Nếu bạn có các sự kiện gọi lại đơn giản không có ranh giới cách ly, thì không có sự bảo vệ nào từ một ứng dụng khách không can thiệp vào việc xử lý của bạn. Quá trình này không thể đảm bảo yêu cầu của nó (để tiếp tục xử lý _correctly_) và nó vô trách nhiệm cho quá trình giả vờ rằng nó có thể. –

+0

Dan: Giả sử đây là tất cả mã được quản lý, bạn mong đợi trình xử lý ngoại lệ bị lỗi để can thiệp vào quy trình chính như thế nào? – Gabe

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