很多人都知道事件,一般定義一個事件是這樣的寫法
public event EventHandler OneEvent;
但是如果這樣定義的話就需要進行null判斷了
于是很多人這樣定義事件:
public event EventHandler OneEventNeverNull = (o, e) => { };
這樣就不需要判斷null了。
上面的事件你可以把它認為是實例事件. 我們這里要談的是靜態事件(static event).
靜態事件和實例事件的區別是加了個static 關鍵字,可別小看這個關鍵字,區別大了。
首先靜態事件的定義為:
public static event EventHandler OneStaticEvent;
如果想要注冊事件的話,那么必須使用類。
在.net 的事件里面,絕大多數是實例事件,但是卻存在極少數的靜態事件。
關于靜態事件StackOverflow 上面有篇文章討論它
地址如下:http://stackoverflow.com/questions/7045595/how-do-static-events-compare-to-non-static-events-in-c
我個人認為答案都不錯,選了幾個,試著翻譯如下:
大部分的面向對象程序都可以被認為是消息的傳遞。
一個方法調用就是調用者發送給被調用者的攜帶參數的一個消息,和一個使用return value 做為返回值的消息。
一個事件是從source到訂閱者的一個消息。因此就有兩個實例參與其中,一個用來發送消息,另一個接收它。
但是靜態事件,沒有發送的實例(只是一個類型,它可能是也可能不是一個class)。
使用 靜態事件的時候,要謹記,當一個對象訂閱了一個靜態事件,事件就持有了這個對象的引用,這就意味著你必須非常小心的顯式的取消訂閱事件,因為靜態事件保留了對象引用,所以這些對象就永遠不會被回收,你很可能碰到內存泄漏。
這些答案都說明了靜態事件的一些特性。總結下:
1:靜態事件沒有發送的實例對象。
2:靜態事件必須取消訂閱,否則對象無法釋放,事實上任何事件都應該取消訂閱,有始有終。
對于第二點沒有什么好考慮的,可是第一點?
靜態事件沒有發送的實例?
a:這代表靜態事件不需要實例就可以,它代表的是類級別的事件。
b:這代表靜態事件沒有實例,或者說無法獲取這個類的實例,所以使用靜態事件。
從這兩個理解,我們可以知道什么時候應該使用靜態事件了。
a:從面向對象的角度,如果一個對象只想獲取事件的通知,而不關心是誰發送的,它只關心事件發生。
b:這個類沒有實例?,什么類沒有實例???,靜態類,抽象類,或者是一些特殊的類。
好了,我不賣關子了,讓我們看看framework里面的靜態事件吧,代碼如下:
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { foreach (Type type in assembly.GetTypes()) { EventInfo[] events = type.GetEvents(BindingFlags.Public | BindingFlags.Static); if (events.Length > 0) { Console.WriteLine(type.ToString()); } } }
結果如下:
微軟的開發人員只為這些類定義了靜態事件,最后一個是我自己寫的,我們看下這些究竟是些什么類。
System.Console
靜態類,無法獲取類的實例,所以靜態事件。
System.Threading.Tasks.TaskScheduler
抽象類,它的靜態事件定義如下:
// 當出錯的 System.Threading.Tasks.Task 的未觀察到的異常將要觸發異常升級策略時發生,默認情況下,這將終止進程。 public static event EventHandler<UnobservedTaskExceptionEventArgs> UnobservedTaskException;
只要應用程序注冊了 UnobservedTaskException 事件,任何TaskScheduler的子類在發生exception的時候,都會通知到應用程序。
System.Diagnostics.Eventing.EventProviderDataStream
沒找到。。。
System.Diagnostics.Contracts.Contract
靜態類,無法獲取類的實例,所以靜態事件。
System.Windows.Forms.Application
密封類,構造函數為私有,外界無法直接獲取Application 的實例。
System.Windows.Forms.ToolStripManager
密封類,構造函數為私有,外界無法直接獲取實例。
System.ComponentModel.TypeDescriptor
密封類,構造函數為私有,外界無法直接獲取實例。
Microsoft.Win32.SystemEvents
密封類,構造函數為私有,外界無法直接獲取實例。
System.Net.NetworkInformation.NetworkChange
密封類,構造函數為私有,外界無法直接獲取實例。
StaticEventDemo.Test
出現的理由:在某天夜晚,我自己想當然的寫下的沒有經過思考的一個靜態事件。
你知道微軟使用靜態事件的策略了嗎?,只有在不能獲取實例的情況下才選擇靜態事件。
有趣的一件事:本人在baidu下搜索:static event, 看到了一篇文章:
net 在類中的Event事件,為什么可以定義為static?而委托類型卻不可以
也可以在這里http://www.2cto.com/kf/201110/108280.html看到代碼。
我看到了下面的這段:
private void button1_Click(object sender, EventArgs e)
{
clsEvent clsevent = new clsEvent();
//改變屬性,從而激發事件。
clsevent.StrContent = this.textBox1.Text;
}
我很想說,在改變屬性前,是不是要注冊點什么啊,我想這就是他為什么定義為static event的原因吧。
總結:
在無法獲取實例的情況下,又想獲得通知,應該使用靜態事件。
不管發送者是誰,只考慮接收事件。
靜態事件一定要取消訂閱,否則內存泄漏。
想要獲取靜態類的通知時,使用靜態事件。
想要得到靜態屬性和方法的通知的時候。
不含病毒。www.avast.com |
留言列表