委託與事件-委託詳解(一)

小世界的野孩子發表於2019-07-19

前言

  說起委託和事件,我就想起了再學校的時候,當時死記硬背去記什麼是委託什麼是事件。記得當時螻某人問我,委託是什麼?但是隻知道一點點,就跟他說:打個比方,我要喝水,但是我不去買,我委託你去幫我買水。這就是委託,夠直白簡單了吧。

委託語法使用

  語法: public delegate void BugWaterEventHandler();

  其中 delegate   是關鍵字,宣告委託的時候命名時字尾加入EventHandle

  這就是一個簡單的委託,就是這麼簡單。我們相對於平時使用的方法有什麼區別吧

  方法:

    

        public static string BuyWaterSlef()
        {
            return "自己去買水";
        }

 

  我們看方法,是實現買水這個功能的,而委託是委託你去幫我買水的。方法是具體做事實現功能,委託只是命令而已。

  我們具體使用委託來實現剛剛那個委託螻某人去買水的程式設計。

  

    /// <summary>
    /// 螻某人去買水的類
    /// </summary>
    public class LouBuy
    {
        /// <summary>
        /// 螻某人買水的方法
        /// </summary>
        /// <returns></returns>
        public static string LouBuyWater()
        {
            return "螻某人去買水";
        }
    }


    /// <summary>
    /// 定義買水的委託
    /// </summary>
    /// <returns></returns>
    public delegate string BuyWater();

 
    /// <summary>
    /// 買水委託實現的類
    /// </summary>
    public class MainBuy
    {
        /// <summary>
        /// 實現委託
        /// </summary>
        /// <returns></returns>
        public static string BuyFun()
        {
            /// 委託中加入螻某人的方法
            BuyWater buyWater = new BuyWater(LouBuy.LouBuyWater);
            ///返回結果
            return  buyWater();
        }     

    }

 

  最後這裡輸出的是”螻某人去買水”

 

  BuyWater buyWater = new BuyWater(LouBuy.LouBuyWater);

  這裡宣告委託方法,BuyWater委託中加入LouBuy.LouBuyWater買水的方法,這個方法引數必須加入,因為委託的建構函式引數不為空。同時需要注意委託引數的返回型別都是要和具體委託方法一樣的。

  在這個例子中都是返回的string,都是無引數的

委託鏈(多播委託)

  上面我們簡單的介紹了下委託及其用法,這裡我們可以瞭解一下委託鏈,顧名思義,委託鏈也就是委託連續,啥意思呢?繼續上面的例子,我委託螻某人去買水,然後順帶買包辣條。

    /// <summary>
    /// 螻某人去買水的類
    /// </summary>
    public class LouBuy
    {
        /// <summary>
        /// 螻某人買水的方法
        /// </summary>
        /// <returns></returns>
        public static void LouBuyWater()
        {
             Console.WriteLine ("螻某人去買水";)
        }

        /// <summary>
        /// 樓某人買辣條方法
        /// </summary>
        /// <returns></returns>
        public static void LouBuyLT()
        {
            Console.WriteLine ("樓某人又買了辣條";)
        }
    }

 
    /// <summary>
    /// 定義買水的委託
    /// </summary>
    /// <returns></returns>
    public delegate void BuyWater();

 
    /// <summary>
    /// 買水委託實現的類
    /// </summary>
    public class MainBuy
    {
        /// <summary>
        /// 實現委託
        /// </summary>
        /// <returns></returns>
        public static void BuyFun()
        {
            /// 委託中加入螻某人的方法
            BuyWater buyWater = new BuyWater(LouBuy.LouBuyWater);
            buyWater += LouBuy.LouBuyLT;
            ///返回結果
             Console.WriteLine (buyWater();)
        }      

    }

 

  這裡就相當於我委託螻某人做了兩件事情,先去買水然後順帶買了辣條,委託鏈(多播委託)可以使用+=來增加委託中呼叫的方法,同理也可使用-=來刪除委託中呼叫的方法.

  注意,委託鏈(多播委託)--委託的簽名必須返回void,否則就只能得到委託呼叫的最後一個方法的結果。同時委託鏈(多播委託)中注意不要呼叫一些必須有特定順序的方法,因為委託中呼叫其方法鏈的順序並未正式定義。

  委託鏈(多播委託)還可能出現一個非常嚴重的問題,也就是在委託中多個方法呼叫時,一旦出現了異常報錯,則整個迭代都會停止。

    

    class Pragram
    {
        static void One()
        {
            Console.WriteLine("one");
            throw new Exception("丟擲異常報錯");
        }

        static void Two()
        {
            Console.WriteLine("two");
        }

 
        public delegate void ActionMain();
        static void Main()
        {
            ActionMain actionMain = One;
            actionMain += Two;
            try
            {
                actionMain();
            }
            catch (Exception)
            {

                Console.WriteLine("異常報錯");

            }
        }
 

    }
    class Pragram
    {
        static void One()
        {
            Console.WriteLine("one");
            throw new Exception("丟擲異常報錯");
        }

        static void Two()
        {
            Console.WriteLine("two");
        }

 
        public delegate void ActionMain();
        static void Main()
        {
            ActionMain actionMain = One;
            actionMain += Two;
            try
            {
                actionMain();
            }
            catch (Exception)
            {

                Console.WriteLine("異常報錯");

            }
        }
 

    }
    class Pragram
    {
        static void One()
        {
            Console.WriteLine("one");
            throw new Exception("丟擲異常報錯");
        }

        static void Two()
        {
            Console.WriteLine("two");
        }

 
        public delegate void ActionMain();
        static void Main()
        {
            ActionMain actionMain = One;
            actionMain += Two;
            try
            {
                actionMain();
            }
            catch (Exception)
            {

                Console.WriteLine("異常報錯");

            }
        }
 

    }
    class Pragram
    {
        static void One()
        {
            Console.WriteLine("one");
            throw new Exception("丟擲異常報錯");
        }

        static void Two()
        {
            Console.WriteLine("two");
        }

 
        public delegate void ActionMain();
        static void Main()
        {
            ActionMain actionMain = One;
            actionMain += Two;
            try
            {
                actionMain();
            }
            catch (Exception)
            {

                Console.WriteLine("異常報錯");

            }
        }
 

    }
    class Pragram
    {
        static void One()
        {
            Console.WriteLine("one");
            throw new Exception("丟擲異常報錯");
        }

        static void Two()
        {
            Console.WriteLine("two");
        }

 
        public delegate void ActionMain();
        static void Main()
        {
            ActionMain actionMain = One;
            actionMain += Two;
            try
            {
                actionMain();
            }
            catch (Exception)
            {

                Console.WriteLine("異常報錯");

            }
        }
 

    }

 

  在這個委託呼叫中,遇到丟擲異常錯誤時就會停止迭代。最終返回結果為

one

丟擲異常報錯

擴充套件延伸

  一、解決多播委託問題

  上面講到多播委託中一個呼叫丟擲異常,整個迭代都會停止。下面講解一個解決此問題的方法。在Delegate類中定義了GetInvocationList()方法,它返回的是Delegate物件陣列,現在可以使用這個委託呼叫與委託直接相關的方法,捕獲異常,並繼續下一次迭代。

    class Pragram
    {
        static void One()
        {
            Console.WriteLine("one");
            throw new Exception("丟擲異常報錯");
        }
        static void Two()
        {
            Console.WriteLine("two");
        }

        public delegate void ActionMain();
        static void Main()
        {
            ActionMain actionMain = One;
            actionMain += Two;
            Delegate[] delegates = actionMain.GetInvocationList();
            foreach (ActionMain item in delegates)
            {
                try
                {
                    item();
                }
                catch (Exception)
                {
 
                    Console.WriteLine("丟擲異常");
                }
            }
        }

    }

 

  再看我們對出現問題的程式碼進行修改,這裡丟擲異常之後會繼續迭代,並不會停止,返回的結果是

one

丟擲異常錯誤

Two

 

 

二、委託其他寫法(Action<T>委託和Fun<T>委託)

  我們上面介紹到委託

public delegate void BuyWater(string a);

BuyWater buyWater = new BuyWater(LouBuy.LouBuyWater);

 

  下面我們介紹另外兩種委託形式,Action<T>委託和Fun<T>委託

  Action<T>委託表示引用一個void返回型別的方法,可以沒有引數,也可以有很多引數,一個引數Action<in T>,l兩個引數Action<in T1,in T2>

Action<string> action=LouBuy.LouBuyWater;

 

  Fun<T>委託表示可以呼叫允許帶返回型別的引數,Fun<out TResult>表示委託型別可以呼叫帶返回型別且無引數的方法,Fun<in T,out TResult>呼叫帶返回型別帶引數的方法

Func<string, string> buyWater = LouBuy.LouBuyWater;//表示返回string型別,引數也是string型別的一個方法

 

總結

  以前總在說委託與事件,都沒有一次去了解熟悉它,現在得好好鞏固一下了。到這裡就介紹完了委託,看上去也挺簡單的。我們下一節繼續看Event事件。然後結合委託一起看看委託加事件如何運用的。

  再長的路,一步步也能走完,再短的路,不邁開雙腳也無法到達。

 

 

 

                      c#基礎知識詳解系列

 

  歡迎大家掃描下方二維碼,和我一起學習更多的C#知識

 

  

 

相關文章