前言
說起委托和事件,我就想起了再學校的時候,當時死記硬背去記什么是委托什么是事件。記得當時螻某人問我,委托是什么?但是只知道一點點,就跟他說:打個比方,我要喝水,但是我不去買,我委托你去幫我買水。這就是委托,夠直白簡單了吧。
委托語法使用
語法: public delegate void BuyWaterEventHandler();
其中 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("異常報錯"); } } }
在這個委托調用中,遇到拋出異常錯誤時就會停止迭代。最終返回結果為
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#知識