C# 委託、事件

C#的Delegate委託可以把方法當做參數傳遞,方便我們回調方法,它的用處很多,爲我們編程提供了很大的便利。而Event又是委託的特殊形式。

委託Delegate

public delegate void GreetingDelegate(string name);
delegate 是委託的關鍵字,GreetingDelegate是一個委託類名,在編譯後,它會由編譯器生成委託類
public sealed class GreetingDelegate:Syste.MulticastDelegate{
public GreetingDelegate(object @object, IntPtr method);
public virtual IAsyncResult BeginInvoke(string name, AsyncCallback callback, object @object);
public virtual void EndInvoke(IAsyncResult result);
public virtual void Invoke(string name);
}

(BeginInvoke和EndInvoke,是對委託異步回調的支持,關於異步回調,會在後面文章中涉及。)

方法定義,此方法只要傳入參數和返回類型與委託定義的一樣,就可以賦值給委託

public void EnglishGreeting(string name)

{

}
首先委託類可以像參數一樣傳遞在方法,屬性中,如下:

public void GreetPeople(string name, GreetingDelegate MakeGreeting)
{
   MakeGreeting(name);
}
然後可以按下面的方式調用此方法:
GreetPeople("Jimmy Zhang", EnglishGreeting); //這代碼看着有點奇怪吧?直接把方法作爲了參數傳遞

委託類是需要實例化的,其實上面的方法內部已經幫你實例化了。它的實例化過程如下:

GreetingDelegate delegate1;
delegate1 = EnglishGreeting;// 以賦值的方式實例化
GreetingDelegate delegate1 = new GreetingDelegate(EnglishGreeting);//以構造方法方式實例化
委託可以通過賦值方式實例化,也可以通過構造方式實例化,GreetPeople("Jimmy Zhang", EnglishGreeting)這裏是通過賦值的方式實例化的

可以將多個方法賦給同一個委託,或者叫將多個方法綁定到同一個委託,當調用這個委託的時候,將依次調用其所綁定的方法。

delegate1 = EnglishGreeting; // 先給委託類型的變量賦值
delegate1 += ChineseGreeting; // 給此委託變量再綁定一個方法
delegate1 -= ChineseGreeting; //當然也可以去掉一個委託方法

Event 事件

public event GreetingDelegate MakeGreet;

定義中多了event關鍵字,GreetingDelegate是上面定義的委託名。它封裝了委託類型的變量,使得在類的內部,不管你聲明它是public還是protected,它總是private的。在類的內部,可以直接調用它。在類的外部,只能使用+=或-=爲它註冊事件的執行方法,不能調用它去執行,這個是類的封裝,只能由內部去觸發事件(但是delegate是可以在外部直接調用,不需要封裝方法的)。

委託事件

按照.Net Framework的編碼規範:委託事件的名稱都應該以EventHandler結束。 委託事件的原型定義:有一個void返回值,並接受兩個輸入參數:一個Object 類型,一個 EventArgs類型(或繼承自EventArgs)。 事件的命名爲 委託去掉 EventHandler之後剩餘的部分。 繼承自EventArgs的類型應該以EventArgs結尾。

定義委託事件的代碼如下:

public delegate void ShowMessageEventHandler(Object sender, MessageEventArgs e); sender參數可以傳遞是誰觸發的,e參數可以自定義一些需要的信息
public event ShowMessageEventHandler ShowMessage; // 命名規範,一般以EventHandler結尾。

定義eventargs
public class MessageEventArgs : EventArgs
{
//內部可以定義自己想要的信息
}

//註冊的方法,方法簽名必須與定義的委託的方法的簽名相同
void EventTest_ShowMessage(object sender, MessageEventArgs e)
{
   Console.WriteLine("you have triggered ShowMessage event");
}

註冊事件

ShowMessage += EventTest_ShowMessage;

註冊的時間可以是new ShowMessageEventHandler(EventTest_ShowMessage),也可以是+=,也可以用-=移出註冊的事件

觸發事件

ShowMessage(this, new MessageEventArgs());//如果在定義此事件的內部類,可以用這種方式直接觸發。

在類的外部想調用ShowMessage,需要封裝成一個方法,雖然是public的,但因爲有event關鍵字,所以是無法編譯通過的。如
   public void TriggerEvent()
        {
            if (ShowMessage != null) {
                ShowMessage(this, new MessageEventArgs("event is from trigger"));
            }
        }

經過測試,對於event事件,定義時也可以是如下的這種形式
        public delegate void NoParamEventHandler();
        public event NoParamEventHandler NoParam;
          
             public void NoParamMethod()
        {
            Console.WriteLine("you have triggered NoParam event");
        }
註冊           
NoParam += NoParamMethod;
觸發
NoParam();
所以對於event與delegate的區別,<pre name="code" class="html">我的理解是雖然可以類似delegate一樣使用,但事件是具有特殊含義的,專門用來處理事件模型,但是最好還是按照clr的編碼規範來定義和使用,這樣方便大家對代碼的閱讀和理解。
順便講一下Func和Action,這2個是已經爲我們定義好了的委託,方便讓我們使用,我們不需要自己定義委託,直接可以用Func<T,TResult>和Action<T>,把簽名一樣的方法賦值
給它們。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章