委託和事件是.Net 框架的重要組成部分,在GUI程式開發中,大量使用了事件處理,但是親們,對於委託,我們是否還記得曾經在書上看到的詳細內容。委託的使用注意事項是什麼?我們會使用委託和事件,但是我們不瞭解事件背後的原理,親們,我們忘記委託了嗎?反正我是忘記了。
委託是方法呼叫的指標,也稱為函式指標,是一種特殊的物件型別,包含的是方法的地址。注意是地址,在.Net 中,委託不同於c++中的函式指標,在C#中 委託是型別安全的操作,這意味著什麼呢?這意味著我們定義的方法簽名必須和委託的定義型別以及返回值一致,否則會出現編譯錯誤的提示資訊。
如何定義一個委託:
delegate int AddDelegate(int x,int y); 委託的定義和類的定義一致,在任何可以定義類的地方都可以定義委託,另外,委託 的實現是繼承自MulticastDelegate 類的,也就是說定義一個委託,基本上等價於定義一個新類。委託類似於方法的定義,但是沒有方法體,只有方法簽名,另外在方法簽名的前面新增了delegate關鍵字。
定義一個簡單的委託例項:
class Program 2 { 3 static void Main(string[] args) 4 { 5 Test t = new Test(); 6 t.Execute(3, 5); 7 Console.Read(); 8 } 9 } 10 11 public class Test 12 { 13 /// <summary> 14 /// 在類的內部定義了一個委託 15 /// </summary> 16 /// <param name="x"></param> 17 /// <param name="y"></param> 18 /// <returns></returns> 19 delegate int AddDelegate(int x, int y); 20 /// <summary> 21 /// 例項方法Add1 和委託具有相同的方法簽名 22 /// </summary> 23 /// <param name="x"></param> 24 /// <param name="y"></param> 25 /// <returns></returns> 26 public int Add1(int x, int y) 27 { 28 Console.WriteLine("Add1計算得到的值為" + (x + y)); 29 return x + y; 30 } 31 /// <summary> 32 /// 靜態方法Add2 和委託具有相同的方法簽名 33 /// </summary> 34 /// <param name="x"></param> 35 /// <param name="y"></param> 36 /// <returns></returns> 37 public static int Add2(int x, int y) 38 { 39 Console.WriteLine("Add2計算得到的值為" + (x + y * 2)); 40 return x + y * 2; 41 } 42 43 public void Execute(int x, int y) 44 { 45 AddDelegate addDelegate = new AddDelegate(Add1); 46 addDelegate += Add2; //通過+= 多播委託 ,表示一個委託例項具有多個方法,多播委託不能保證方法的執行順序。 47 addDelegate(x, y); 48 } 49 /// <summary> 50 /// 多播委託在其中一個呼叫方法出現異常時會停止迭代,我們優先採用下面方法,即逐個的呼叫 方法列表執行,可以避免由於某個呼叫方法出現異常,導致其他呼叫方法無法執行的問題 51 /// </summary> 52 /// <param name="x"></param> 53 /// <param name="y"></param> 54 public void Execute3(int x, int y) 55 { 56 AddDelegate addDelegate = new AddDelegate(Add1); 57 addDelegate += Add2; //通過+= 多播委託 ,表示一個委託例項具有多個方法,多播委託不能保證方法的執行順序。 58 if (addDelegate != null) 59 { 60 Delegate[] addArr = addDelegate.GetInvocationList();//獲取多播委託的呼叫列表 61 if (addArr != null) 62 { 63 foreach (var item in addArr) 64 { 65 ((AddDelegate)item)(x, y); 66 } 67 } 68 } 69 } 70 public void Execute1(int x, int y) 71 { 72 AddDelegate addDelegate = Add1;//直接為委託例項賦值方法簽名 稱為委託推斷 .Net 編譯器會識別委託簽名 73 addDelegate += Add2; 74 addDelegate(x, y); 75 } 76 }
例項總結:
- addDelegate =Add1 這種為委託例項賦值的方式稱為 委託推斷,是由.Net 編譯器自動推斷方法簽名是否符合委託。
- 委託可以通過+= 來實現一個委託例項具有多個呼叫方法執行,請注意,多播委託的執行不能保證順序,即不能保證方法註冊的次序和呼叫次序一致。2.多播委託在執行過程中,如果某個呼叫方法出現異常,則整個多播委託的呼叫方法列表都會停止執行,我們可以採用Execute3 展示的那樣,逐個手動執行呼叫方法列表,避免由於某個呼叫方法出現異常,導致其他呼叫方法不會執行的問題。
- 委託例項的方法即可以是例項方法,又可以是靜態方法,只要保證方法簽名一致就可以正常的呼叫。
- 委託可以作為引數傳遞,下面我們會展示一個通過將委託作為例項,來實現排序的功能。
- 委託可以具有訪問修飾符public、protected以及private等。
- 可以通過委託的簡便方式,匿名方法來直接定義一個方法到委託例項,.Net 編譯器會幫助我們生成一個隨機的方法名稱,只是我們不需要。
- lambda 也可以應用到委託中,通過lambda表示式生成的是匿名方法,或者說是匿名委託。