前言
說起委託和事件,我就想起了再學校的時候,當時死記硬背去記什麼是委託什麼是事件。記得當時螻某人問我,委託是什麼?但是隻知道一點點,就跟他說:打個比方,我要喝水,但是我不去買,我委託你去幫我買水。這就是委託,夠直白簡單了吧。
委託語法使用
語法: 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#知識