[英]Raising Events in C#: performance and elegance
習慣於VB.NET,我習慣於“只是舉起事件”。 當然,自定義事件有所不同,但有“常規”事件 - 我不需要在提升之前檢查代表是否為Nothing
。
使用C#,我發現自己重復這種模式:
if (myHandler != null)
{
myHandler(this, new EventArgs());
}
我以為以下模式可能會更優雅:
myHandler = (sender, e) => { };
myHandler(this, new EventArgs());
這種模式會比前一種模式更多或更少嗎? 我還應該考慮其他重要因素嗎?
這在建築中是額外的事情,但它不會是巨大的開銷。 需要注意的一點是,某些序列化框架(如DataContractSerializer
(WCF))不運行構造函數或字段初始值設定項,因此它可能不是非null。 就個人而言,如果您的大多數事件都是EventHandler
,我可能會想要使用擴展方法:
public static void SafeInvoke(this EventHandler handler, object sender) {
if (handler != null) handler(sender, EventArgs.Empty);
}
然后:
SomeEvent.SafeInvoke(this);
雖然坦率地說,我很少使用null-check來解決問題; p
另一個缺點是,如果你有足夠的事件,這是一個問題,你可能應該使用EventHandlerList
- 而這種方法不適用於EventHandlerList
。
通常的做法是使用受保護的虛方法OnEventName,您可以在其中檢查事件是否為null並將其提升:
protected virtual void OnEventName(parameters)
{
if (EventName != null)
EventName(this, new EventNameEventArgs(parameters);
}
這允許您將所有事件引發代碼放在一個位置(無空檢查重復),並在以后根據需要覆蓋它。 因此,對於每個事件添加一個虛擬事件處理程序而不是每個事件進行一次空檢查,我看不出任何好處。
BTW更短的添加虛處理程序的方法是myHandler = delegate {};
不要認為提供的第一和第二種情況之間存在顯着差異,至少不要考慮它們。 過於頻繁地使用委托,缺少if (myHandler != null)
順便說一句,可以帶來一些性能上的好處。 因此,如果您確定處理程序永遠不會為 null
,那么擺脫控制權基本上就完成了。
我認為兩種方法之間的性能差異不夠大 ,無法相關。 如果有的話,我會爭辯說,null檢查比通過委托調用方法更便宜 ,即使它是無操作。
在談論優雅時 ,應該指出VB.NET中的RaiseEvent
關鍵字會被編譯器自動擴展為完全相同的構造,您必須在C#中自己編寫:
If (Not MyEvent Is Nothing) Then
MyEvent.Invoke(New EventArgs())
End If
如果您想避免在整個代碼中重復該構造,可以將其封裝在幾個擴展方法中:
public static void RaiseEvent(this EventHandler source, object sender)
{
if (source != null)
{
source.Invoke(sender, new EventArgs());
}
}
public static void RaiseEvent<T>(this EventHandler<T> source, object sender, T eventArgs)
where T : EventArgs
{
if (source != null)
{
source.Invoke(sender, eventArgs);
}
}
那樣你就可以簡單地說:
myEvent.RaiseEvent(this);
myOtherEvent.RaiseEvent(this, new SomeEventArgs());
它在語義上等同於VB.NET中使用的樣式。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.