2010-12-08 45 views
1

我可能會對此稍加反思,但我可以使用一些幫助來確定一種方法/執行以下操作的最佳方法。將變量捕獲到事件處理程序中

我有一個事件處理程序附加到另一個類的屬性的對象。在我的事件處理函數中,我需要關於引起事件的對象的附加元數據(即包含它的對象的ID)。從發件人和活動信息無法獲取我需要的信息。我的傾向是,這將是一個使用捕獲變量的好地方,但我不確定我的實現想法。

所以在代碼中說明我有一個事件處理程序:

void MyEventHandler(object sender, EventArgs e){ 
    //Do Stuff here 
} 

(由於我使用基地的EventArgs在這裏,但我的實際執行情況的說明的是一個專門的子類,並使用聲明的事件通用事件處理程序)

我目前安裝這樣的:

topObject.SubObject.EventToHandle += MyEventHandler; 

我後來detatch它像這樣:

topObject.SubObject.EventToHandle -= MyEventHandler; 

我想topObject的,當我處理事件,所以我準備換一個MyEventHandler有以下特徵碼編號:

void MyEventHandler(int id, object sender, EventArgs e) 

和附加事件處理程序是這樣的:

topObject.SubObject.EventToHandle += (s,e) => MyEventHandler(topObject.ID, s,e); 

我對此的擔憂是雙重的。

  1. 是否有問題的範圍,處理程序將實際消失而不會刪除,一旦我在這附加功能之外。我以前在使用lambda表達式時發現了一些奇怪的錯誤,在這些錯誤中事件處理程序在我身上消失了。並非所有的時候,只是在某些情況下。任何人都可以啓發我這些案件可能是什麼,所以我知道它何時可以安全地使用我的語法。
  2. 我不記得確切,但我不認爲如果我使用這種語法,我可以刪除事件處理程序,因爲創建的隱式對象不相同。

由於這兩個問題,我的想法是創建一個Action並保存該操作並使用它,直到我需要刪除該事件處理程序。我做了以下內容:

Action<object, EventArgs> handler = (s,e) => MyEventHandler(topObject.ID, s,e); 
topObject.SubObject.EventToHandle += handler; 

我得到的行動不能被鑄造到事件處理程序。是否有一些簡單的方法可以進行這種轉換,以確保我可以分離事件處理程序?我剛剛想過這個/有沒有一種方法我現在沒有看到這樣做?

回答

1

您可以創建所有漂亮的包裝函數,它們包裝現有的事件處理程序併爲它們提供對象標識符,但是您仍然必須顯式存儲結果委託以取消訂閱事件。

我看到沒有醜陋的包裝的唯一不錯的方式是使用反應式擴展。它基本上允許您將事件轉換爲IObservable,然後您可以將任何操作符應用於生成的IObservable(例如,Select將按照您的情況執行此任務)。但它仍然沒有那麼優雅。

0

引發事件的類的事件處理程序的簽名應該是:

protected void OnMyEvent(object sender, EventArgs e) 
{ 
    .... 
} 

protected void OnMyEvent(object sender, MyEventArgs e) 
{ 
    .... 
} 

在這種情況下,主叫方會做這樣的代碼:

topObject.SubObject.MyEvent -= OnSubObjectMyEvent; 

並像這樣實現OnSubObjectMyEvent(示例):

private void OnSubObjectMyEvent(object sender, MyEventArgs e) 
{ 
    int topObjectId = ((SubObjectType)sender).TopObject.Id; 
    ... 
} 

這裏我假設SubObject有一個TopObject屬性,它允許我獲取頂層對象的ID。

這就是大多數.NET框架類的工作方式。這種方法有什麼問題嗎?

+1

有什麼不妥的做法是我處理我不控制的對象,並且子對象不知道它的topobject。如果我有這個訪問權限,這個cleary將是一個非問題 – 2010-12-09 13:17:38

0

如果事件處理程序需要頂級對象的ID,我猜想它不會破壞設計中的某個抽象層,以使它們知道彼此。

換句話說,你的事件處理程序可以是這樣的:

void Handler(object sender, EventArgs e) 
{ 
    var s = (SubObject) sender; 
    int id = s.TopObject.ID; 

    // do something with id... 
} 

,我要不斷的事件簽名在發送者和args的約定。

0

不要更改事件的簽名。雖然CLR在技術上允許對任何事件進行簽名,但爲什麼整個框架設計的簽名爲(object sender, EventArgs args)的事件是有原因的。事實上,對於違反此簽名活動,CA1009: Declare event handlers correctly的FxCop的規則:

事件處理方法需要兩個 參數。第一個是 System.Object類型,名爲'sender'。 這是引發 事件的對象。第二個參數是 System.EventArgs類型,名稱爲'e'。

有幾種解決方案(方案):

  • 通過topObject.ID作爲您的自定義EventArgs的成員。
  • 創建封裝對象,該對象封裝了topObject.ID並將事件處理程序掛接到此對象的方法。
  • 使用封閉範圍,可以保留提及topObject.ID範圍(這與上述方法相同,但heavylifting是由編譯器完成)
相關問題