close
文章出處

很多人都知道事件,一般定義一個事件是這樣的寫法

public event EventHandler OneEvent;

但是如果這樣定義的話就需要進行null判斷了

825E6B5E43014CC898E20B3BFDFC1B00

于是很多人這樣定義事件:

public event EventHandler OneEventNeverNull = (o, e) => { };

 

這樣就不需要判斷null了。

 

上面的事件你可以把它認為是實例事件. 我們這里要談的是靜態事件(static event).

靜態事件和實例事件的區別是加了個static 關鍵字,可別小看這個關鍵字,區別大了。

 

首先靜態事件的定義為:

public static event EventHandler OneStaticEvent;

 

如果想要注冊事件的話,那么必須使用類。

image

 

在.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());
        }
    }
}
結果如下:
00815F6C3CA84DEE9B7FA34A64EB9BB2
 

 

微軟的開發人員只為這些類定義了靜態事件,最后一個是我自己寫的,我們看下這些究竟是些什么類。

 

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
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 AutoPoster 的頭像
    AutoPoster

    互聯網 - 大數據

    AutoPoster 發表在 痞客邦 留言(0) 人氣()