2009-01-12 80 views
8

我遇到了什麼是一個常見的問題。當我有一個可能由幾個不同的類訂閱的事件時,由這些類之一拋出的異常將會終止回調鏈;因爲我不知道按照什麼順序進行回調,這可能會導致某些類的狀態發生不可預知的變化,而對其他類不會發生。如何阻止異常垃圾我的委託鏈?

在聖經中(CLR via C#,我使用的是C#2.0),有一個關於使用MulticastDelegate.GetInvocationList來解決這個問題的簡短的段落,但僅此而已。所以我的問題是:處理這個問題的最好方法是什麼?每次有事件時,我必須使用MulticastDelegate.GetInvocationList嗎?或者我是否需要將所有可能作爲代理鏈的一部分調用的方法放在某種回滾機制中?爲什麼所有這些選項與在C#中很容易使用的簡單事件/委託模型相比如此複雜?我怎樣才能使用簡單的方式,而不會結束損壞的狀態?

謝謝!

+0

注意回覆您的評論 – 2009-01-12 10:09:12

回答

11

如果您只是調用委託,它將按順序調用所有目標方法。您需要使用GetInvocationList如果你想單獨執行它們 - 例如:

  • 每個
  • 後檢查Cancel捕捉到的每一個
  • 返回值的單個目標的失敗後繼續

至於使用它的最佳方式:你希望它的行爲如何?目前尚不清楚我...例如,這可能適合擴展方法相當不錯:

static void InvokeIgnoreErrors(this EventHandler handler, 
     object sender) { 
    if(handler != null) { 
     foreach(EventHandler subHandler in handler.GetInvocationList()) { 
      subHandler(sender, EventArgs.Empty); 
     } 
    } 
} 

然後,你可以調用myHandler.InvokeIgnoreErrors(this);(例如)。

另一個例子是:

static bool InvokeCheckCancel(this CancelEventHandler handler, 
     object sender) { 
    if(handler != null) { 
     CancelEventArgs args = new CancelEventArgs(false); 
     foreach(CancelEventHandler subHandler in handler.GetInvocationList()) { 
      subHandler(sender, args); 
      if(args.Cancel) return true; 
     } 
    } 
    return false; 
} 

第一個事件之後停止請求取消。

+0

好的,這對於擴展方法來說似乎是一個不錯的用處。不幸的是,我陷入了C#2.0 - 我有什麼想法可以在這裏優雅地做到這一點?謝謝! – 2009-01-12 09:33:34

+1

然後,只需使用靜態方法。刪除「this」,並使用YourUtilityClass.InvokeIgnoreErrors(myHandler,this); – 2009-01-12 10:08:41

1

與其改變你如何調用事件,我認爲你應該檢查你的事件處理程序。在我看來,事件處理程序方法應該總是寫出來,以便它們「安全」並且絕不會讓異常傳播。當你在外部代碼調用事件的GUI代碼中處理事件時,這是特別重要的,但是這是一個隨時都有的好習慣。

相關問題