委托和事件是.Net 框架的重要組成部分,在GUI程序開發中,大量使用了事件處理,但是親們,對於委托,我們是否還記得曾經在書上看到的詳細內容。委托的使用注意事項是什麼?我們會使用委托和事件,但是我們不了解事件背後的原理,親們,我們忘記委托了嗎?反正我是忘記了。
委托是方法調用的指針,也稱為函數指針,是一種特殊的對象類型,包含的是方法的地址。注意是地址,在.Net 中,委托不同於c++中的函數指針,在C#中 委托是類型安全的操作,這意味著什麼呢?這意味著我們定義的方法簽名必須和委托的定義類型以及返回值一致,否則會出現編譯錯誤的提示信息。
如何定義一個委托:
delegate int AddDelegate(int x,int y); 委托的定義和類的定義一致,在任何可以定義類的地方都可以定義委托,另外,委托 的實現是繼承自MulticastDelegate 類的,也就是說定義一個委托,基本上等價於定義一個新類。委托類似於方法的定義,但是沒有方法體,只有方法簽名,另外在方法簽名的前面添加了delegate關鍵字。
定義一個簡單的委托實例:
1 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 }
實例總結:
我們來定義一個將委托作為參數傳遞,實現排序的功能。目前我們的需求是創建一個通用類庫,其中有一個可以將數組中的內容按升序排列,但是數組的數據類型我們可以自定義,也就是說,我們不能指定數組的數據類型為某一種具體類型,可以為int、double ,也可以為類。
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 //Test t = new Test(); 6 //t.Execute(3, 5); 7 List<string> listInt = new List<string>(); 8 9 List<Employee> listEmployee = new List<Employee>(); 10 for (int i = 10; i >= 0; i--) 11 { 12 listInt.Add(i.ToString()); 13 Employee employee = new Employee() 14 { 15 Name = i.ToString(), 16 Salary = i 17 }; 18 listEmployee.Add(employee); 19 } 20 Test1 test1 = new Test1(); 21 Employee[] arrEmployee = listEmployee.ToArray(); 22 test1.Sort(arrEmployee, test1.CompareEmployee); 23 24 foreach (var item in arrEmployee) 25 { 26 Console.WriteLine(item.Salary); 27 } 28 29 string[]arrInt=listInt.ToArray(); 30 test1.Sort(arrInt, test1.CompareInt); 31 foreach (var item in arrInt) 32 { 33 Console.WriteLine(item); 34 } 35 36 37 38 Console.Read(); 39 } 40 } 41 public class Test1 42 { 43 44 /// <summary> 45 /// 委托 比較兩個值的大小 x>y 返回true 46 /// </summary> 47 /// <param name="x"></param> 48 /// <param name="y"></param> 49 /// <returns></returns> 50 public delegate bool Compare(object x, object y); 51 52 public void Sort(object[] arrObj, Compare compare) 53 { 54 for (int i = 0; i < arrObj.Length; i++) 55 { 56 for (int j = i+1; j < arrObj.Length; j++) 57 { 58 if (compare(arrObj[i], arrObj[j])) 59 { 60 object temp = arrObj[i]; 61 arrObj[i] = arrObj[j]; 62 arrObj[j] = temp; 63 } 64 } 65 } 66 } 67 68 69 public bool CompareEmployee(object em1, object em2) 70 { 71 if (em1 != null && em2 != null) 72 { 73 return ((Employee)em1).Salary > ((Employee)em2).Salary; 74 } 75 return false; 76 } 77 78 public bool CompareInt(object x, object y) 79 { 80 return Convert.ToInt32(x) > Convert.ToInt32(y); 81 } 82 83 } 84 /// <summary> 85 /// 員工類 86 /// </summary> 87 public class Employee 88 { 89 /// <summary> 90 /// 員工姓名 91 /// </summary> 92 public string Name { get; set; } 93 /// <summary> 94 /// 員工工資 95 /// </summary> 96 public int Salary { get; set; } 97 }
總結:
委托作為事件的基礎,本身 只具有簡單的一些概念,但是我覺得要真正的在實際項目中可以靈活的使用,還是需要深入思考,做個好夢