C# 委託和事件

1.委託/delegate

 類似於C++中的函數指針(一個指向內存位置的指針)。委託是C#中類型安全的,可以訂閱一個或多個具有相同簽名方法的函數指針。
 簡單理解,委託是一種可以把函數當做參數傳遞的類型。很多情況下,某個函數需要動態地去調用某一類函數,這時候我們就在參數列表放一個委託當做函數的佔位符。
 在某些場景下,使用委託來調用方法能達到減少代碼量,實現某種功能的用途。

1.1 自定義委託

 聲明和執行一個自定義委託,大致可以通過如下步驟完成:
1.利用關鍵字delegate聲明一個委託類型,它必須具有和你想要傳遞的方法具有相同的參數和返回值類型
2.創建委託對象,並且將你想要傳遞的方法作爲參數傳遞給委託對象;
3.通過上面創建的委託對象來實現該委託綁定方法的調用

1.2 多薄委託

 一個委託可以引用多個方法,包含多個方法的委託就叫多播委託。
 多播委託的聲明過程是和自定義委託一樣的,可以理解爲,多播委託就是自定義委託在實例化時通過 “+=” 符號多綁定了兩個方法
 “+=”的本質是調用了Delegate.Combine方法,該方法將兩個委託連接在一起,並返回合併後的委託對象。

 class Program
    {
        //1.使用delegate關鍵字聲明委託
        private static void EnglishGreeting(string name)
        {
            Console.WriteLine("Morning." + name);
        }

        private static void ChineseGreeting(string name)
        {
            Console.WriteLine("早上好." + name);
        }

        //它接受一個GreetingDelegate類型的方法作爲參數
        private static void GreetPeople(string name, GreetingDelegate MakeGreeting)
        {
            MakeGreeting(name);
        }


        static void Main(string[] args)
        {
            //GreetPeople("J-Will", EnglishGreeting);
            //GreetPeople("張三", ChineseGreeting);
            //Console.ReadKey();

            /*
            GreetingDelegate delegate1;
            delegate1 = EnglishGreeting;// 先給委託類型的變量賦值
            delegate1 += ChineseGreeting;// 給此委託變量再綁定一個方法
            delegate1("j will");            
            GreetPeople("j will", delegate1);// 將先後調用 EnglishGreeting 與 ChineseGreeting 方法
            */

            //2.實例化這個委託,並引用方法
            GreetingDelegate dlg_1 = new GreetingDelegate(EnglishGreeting);
            //簡寫爲: GreetingDelegate dlg_1 = EnglishGreeting;
            dlg_1 += ChineseGreeting;  // += : 給此委託變量再綁定一個方法(多播)
            dlg_1("j will");
            Console.ReadKey();
            Console.WriteLine("______分隔______");
            dlg_1 -= ChineseGreeting; //  -= : 取消對EnglishGreeting方法的綁定
            dlg_1("j will");
        }
    }

 對於有返回值的方法需要我們從委託列表上手動調用。否則,就只能得到委託調用的最後一個方法的結果。
 正確做法:利用GetInvocationList獲得委託列表上所有方法,循環依次執行委託,並處理委託返回值。

           //獲取委託鏈上所有方法
            Delegate[] delList = del.GetInvocationList();
            //遍歷,分別處理每個方法的返回值
            foreach (GetStrDelegate item in delList)
            {
                //執行當前委託
                string result = item();
                Console.WriteLine(result);
                //控制檯輸出結果:
                //You called me from Func1
                //You called me from Func2
                //You called me from Func3
            }
            Console.ReadKey();

1.3 匿名方法

 簡化委託的聲明。假如委託引用的方法只使用一次,那麼就沒有必要聲明這個方法,這時用匿名方法表示即可。

GreetingDelegate dlg_1 = delegate(string str) { return str.ToUpper(); };    //直接在簽名中寫方法內容
            string result = dlg_1 ("KaSlFkaDhkjHe");

 通常在下面情況下使用:
1.委託需要指定一個臨時方法,該方法使用次數極少;
2.這個方法的代碼很短,甚至可能比方法聲明都短的情況下使用。

1.4 內置委託

 微軟直接把定義委託這一步驟封裝好,形成三個泛型類:Action、Func和Predicate,省去了定義的步驟。

public class Program
    {
        public static void Main(string[] args)
        {
            //Action
            Action<string> action = delegate(string str) { Console.WriteLine("你好!" + str); };
            action("GG");

            //Func
            Func<int, int, int> func = delegate(int x, int y) { return x + y; };
            Console.WriteLine("計算結果:" + func(5, 6));

            //Predicate
            Predicate<bool> per = delegate(bool isTrue) { return isTrue == true; };
            Console.WriteLine(per(true));
        }
    }

Action委託:允許封裝的方法有多個參數,不能有返回值;
Func委託:允許封裝的方法有多個參數,必須有返回值;
Predicate委託:允許封裝的方法有一個參數,返回值必須爲bool類型。

2.事件/event

 委託是一種類型,事件依賴於委託,故事件可以理解爲是委託的一種特殊實例。
 委託可以在任意位置定義和調用,但是事件只能定義在類的內部,只允許在當前類中調用。所以說,事件是一種類型安全的委託
 

本文絕大部分轉自http://www.cnblogs.com/gao-yang/p/5493028.html,感謝博主gao-yang。

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