2009-04-30 55 views
16

請考慮這種情況。我有一個對象,讓我們叫它...... Foo。 Foo提出了一個名爲「Loaded」的簡單事件。作爲事件信息的一部分,消費者需要知道哪個foo對象引發了事件。我們的團隊採用了以下模式。C#簡單事件提升 - 使用「發件人」與自定義EventArgs

1)創建一個繼承自EventArgs的新類 - 例如, FooEventArgs:System.EventArgs。

2)將Foo類型的屬性添加到FooEventArgs中,該屬性通過構造函數傳入。

3)使用事件處理程序的通用版本聲明事件,所以

public event EventHandler<FooEventArgs> Loaded; 

4)提高從Foo類具有以下簽名的事件:

Loaded(this, new FooEventArgs(this)); 

本質上講這確實是使得「發件人」成爲foo對象,但它也將foo對象引用放入事件參數中作爲強類型屬性。

這樣做的一個好處是,沒有人在處理事件時不必擔心投射「發件人」,這會降低事件消費者與事件提升者之間的耦合度。另一個「優點」是,如果事件提升者的類型必須改變,並且因此強類型屬性(希望永不會發生),那麼不是簡單地在代碼開始失敗時拋出它爲空, API實際上會中斷,因此它可以在編譯時修復。

對我來說,這種模式似乎可能是矯枉過正。他們是否應該更多地信任「sender」參數,並且拋棄自定義事件參數?我的團隊認爲沒有人真的使用sender參數。傳遞引發事件的對象的最佳做法是什麼?

編輯:到目前爲止的很好的反饋,我會離開這個開放一天左右,然後我接受一個。

+4

對於另一種方法來此,你可能想看看「事件簽名在.NET中 - 使用強類型的「發件人」?這裏:http://stackoverflow.com/questions/1046016/event-signature-in-net-using-a-strong-typed-sender – 2009-08-23 13:26:45

回答

9

常見模式是使用發件人而不是將發件人單獨添加到EventArgs。自定義EventArgs用於其他狀態,如樹事件的樹節點,可撤消事件的(可設置的)布爾值等。

我們使用通用模式,因爲它也被BCL類使用, 「自制事件」的差異可能會令人困惑。另外,我們有一個全局的IoC發佈者 - 訂閱者模式,但是這個模式只能用於正常的EventHandler委託簽名,因爲這些類型事先並不知道。在這種情況下,無論如何都需要強制轉換(例如對於自定義EventArgs),所以我們可能也會發送該發送者。

2

我會說約定有很多事情要做。從長遠來看,維持的時間更少 - 尤其是。如果你得到新的人。

2

我想這是一個偏好的問題,但在我的情況下,當我看到consumers will need to know which foo object raised the event.我立即認爲你可以從發件人參數引發事件的對象,那麼什麼是問題?

你的團隊有一些有效點(擁有強類型屬性),但我認爲從長遠來看,使用框架指南而不是發明自己的框架將是一個更好的決策。

3

我不認爲這是矯枉過正。我同意你有一個獨立的FooEventArgs類的優點。這樣做的另一個好處是,如果將來需要向事件添加更多信息,則可以將更多屬性添加到FooEventArgs中,並且不需要更改委託。

+0

「我相信這也是一個建議微軟做法這樣做」 - 做你有什麼參考? – Lucero 2009-04-30 23:51:11

+0

絕對推薦的做法是使用EventArgs的子類向事件添加其他信息。請參閱:http://msdn.microsoft.com/en-us/library/aa645739(VS.71).aspx或http://www.codeproject.com/KB/cs/event_fundamentals.aspx。至於將發件人添加到eventargs ...這就是爲什麼我問:p – womp 2009-04-30 23:55:40

3

我想說你放棄EventArgs的子類並使用sender屬性來標識事件的發送者。我認爲遵循慣例的論點具有優點,但EventArgs中的參數不是必需的。我個人會放棄它,只使用sender屬性。

如果你想要把它作爲一個強類型的,你也可以只創建一個自定義委託使用爲您的活動......

public delegate void LoadedHandler(FooEventArgs args); 

這樣你可以有它作爲一個強類型.. 。重用委託很棒,但如果它們不適合你正在嘗試做的事情,你不應該僅僅使用內置的委託。

2

就推薦的做法而言,我已經看到null在Windows Workflow Foundation中作爲發件人提供了相當多的內容。理想情況下,您的訂閱者應該忘記引發事件的對象。

因此,如果您需要將調用者對象作爲整體傳遞給處理程序,則必須將其放入EventArgs派生對象中。或者,我更願意明確地傳遞事件提升者/調用者的狀態,而不是整個事情。

好,有時更容易想到的dotnet 1.1,其中

Control.Invoke() 

被頻繁使用

int i;