C# EventHandler and Delegate(委託的使用)

 委託的聲明

public delegate void MyDelegate(string str);

1、委託的定義和方法的定義類似,只是在前面加了一個delegate,但委託不是方法,它是一種特殊的類型,看成是一種新的對象類型比較好理解。用於對與該委託有相同簽名的方法調用。
2、委託相當於C++中的函數指針,但它是類型安全的。
3、委託是從System.Delegate派生,但不能象定義常規類型一樣直接從System.Delegate派生,對委託的聲明只能通過上面的聲明格式進行定義。關鍵字delegate通知編譯器這是一個委託類型,從而在編譯的時候對該類進行封裝,對這一過程C#定義了專門的語法來處理這一過程。
4、不能從一個委託類型進行派生,因爲它也是默認sealed的。
5、委託即可以對靜態方法進行調用也可以對實例方法進行調用。
6、每個委託類型包含一個自己的調用列表,當組合一個委託或從一個委託中刪除一個委託時都將產生個新的調用列表。
7、兩個不同類型的委託即使它們有相同的簽名和返回值,但還是兩個不同類型的委託。但其實在使用中可看作是相同的。


委託的比較

C#中對委託定義了兩個操作符 == 和 !=
在以下情況下兩個委託是相等的:
1、當兩個委託都同時爲null的時候;
2、當兩個委託都不爲null時,下列情況下是相等的。
     a、當兩個委託的各自的調用列表只含有一個入口點的時候,在下列情況下是相等的:
     (1) 調用同一對象的同一靜態方法
     (2) 調用同一對象的同一實例方法
     b、當兩個委託具有多個入口點時, 在下列情況下是相等的:
     (1)只有當它們調用列表中的調用的方法按順序都一一對應相同的對象及對象的同一方法的時候,如上所述的兩個不同類型的委託但是它們具有相同的簽名和返回值時,只要滿足上述條件的,即使它們類型不同,但比較的結果也是相同的。

 

委託的異常處理

當調用該委託的方法中發生了異常時,首先在調用該委託的方法中搜尋catch語句塊。如果沒有,則去該委託調用的方法中去尋找有沒有catch語句塊,這和調用方法發生異常的處理是一樣的。

當調用一個爲null的委託即委託中列表中不存在調用方法時,將發生NullRefrenceException

 

委託的注意點
當一個委託有多個入口點的時候,調用委託將依該委託的調用列表中的方法的順序依次調用.這些方法共享一個參數集合,所以當委託有返回值的時候調用完這個委託後的返回值是最後一個方法的返回值或是有out參數.如果該委託的參數爲ref(引用類型),那麼在招待第一個方法的時候如果對這個參數的值有所改變,那麼這個改變將會影響到後面的方法調用。

 

委託的一個例子

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            // 創建一個委託實例,封裝C類的靜態方法M1
            MyDelegate d1 = new MyDelegate(C.M1);
            d1("D1"); // M1

            // 創建一個委託實例,封裝C類的靜態方法M2
            MyDelegate d2 = new MyDelegate(C.M2);
            d2("D2"); // M2

            // 創建一個委託實例,封裝C類的實例方法M3
            MyDelegate d3 = new MyDelegate(new C().M3);
            d3("D3"); // M3

            // 從一個委託d3創建一個委託實例
            MyDelegate d4 = new MyDelegate(d3);
            d4("D4"); // M3

            // 組合兩個委託
            MyDelegate d5 = d1 + d2;
            d5 += d3;
            d5("D5"); // M1,M2,M3

            // 從組合委託中刪除d3
            MyDelegate d6 = d5 - d3;
            d6("D6"); // M1,M2
            d6 -= d3; // 雖然d6調用列表中已經沒有d3了,但這樣只是不可能的移除沒有錯誤發生
            d6("D6"); // M1,M2
            d6 -= d6;
            //d6("D6"); 此時d6的調用列表爲空,d6爲null,所以引發System.NullReferenceException

            MyDelegate d7 = new MyDelegate(C1.P1);
            d7("D7"); // C1.P1

            MyDelegate d8 = new MyDelegate(new C2().P1);
            d8("D8"); // C2.P1

        }
    }

    // 聲明一個委託MyDelegate
    public delegate void MyDelegate(string str);

    public class C
    {
        public static void M1(string str)
        {
            Console.WriteLine("From:C.M1:   {0}", str);
        }

        public static void M2(string str)
        {
            Console.WriteLine("From:C.M2:   {0}", str);
        }

        public void M3(string str)
        {
            Console.WriteLine("From:C.M3:   {0}", str);
        }
    }

    public class C1
    {
        public static void P1(string str)
        {
            Console.WriteLine("From:C1.P1:   {0}", str);
        }
    }

    public class C2
    {
        public void P1(string str)
        {
            Console.WriteLine("From:C2.P1:   {0}", str);
        }
    }   
}

事件委託

事件概述

事件就是當對象或類狀態發生改變時,對象或類發出的信息或通知。發出信息的對象或類稱爲"事件源",對事件進行處理的方法稱爲"接收者",通常事件源在發出狀態改變信息時,它並不知道由哪個事件接收者來處理.這就需要一種管理機制來協調事件源和接收者,C++中通過函數指針來完成的.在C#中事件使用委託來爲觸發時將調用的方法提供類型安全的封裝


事件的聲明

1.聲明一個委託
public delegate void EventHandler(object sender, System.EventArgs e);

2.聲明一個事件
public event EventHandler Changed;

3.引發一個事件
public OnChanged(EnventArgs e)
{
 if ( Changed != null)
 {
  Changed(this,e);
 }
}

4.定義事件處理程序
public MyText_OnChanged(Object sender,EventArgs e)
{
 ...
}

5.訂閱事件(將事件處理程序添加到事件的調用列表中)

myText.Changed += EventHandler(MyText_OnChanged);

下面的一個小例子說明了怎樣定義一個完整的事件機制:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {       
        static void Main(string[] args)
        {             
            MyText myText = new MyText();

            // 將事件處理程序添加到事件的調用列表中(即事件佈線)
            myText.Changed += new MyText.ChangedEventHandler(myText_Changed);        
           
            string str = "";
            while (str != "quit")
            {
                Console.WriteLine("please enter a string:");
                str = Console.ReadLine();
                myText.Text = str;
            }
        }

        // 對Change事件處理的程序
        private static void myText_Changed(object sender, EventArgs e)
        {
            Console.WriteLine("text has been changed  :{0}\n" ,((MyText)sender).Text);
        }       
    } 

    public class MyText
    {
        private string _text = "";

        // 定義事件的委託
        public delegate void ChangedEventHandler(object sender, EventArgs e);

        // 定義一個事件
        public event ChangedEventHandler Changed;

        // 用以觸發Change事件
        protected virtual void OnChanged(EventArgs e)
        {
            if (this.Changed != null)
                this.Changed(this, e);
        }

        // Text屬性
        public string Text
        {
            get { return this._text; }
            set
            {
                this._text = value;
                // 文本改變時觸發Change事件
                this.OnChanged(new EventArgs());
            }
        }
    }
}  

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