委托和事件是.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 Test12 {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 = i17 };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 Test142 {43 44 /// <summary>45 /// 委托 比较两个值的大小 x>y 返回true46 /// </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 Employee88 {89 /// <summary>90 /// 员工姓名91 /// </summary>92 public string Name { get; set; }93 /// <summary>94 /// 员工工资95 /// </summary>96 public int Salary { get; set; }97 }
总结:
委托作为事件的基础,本身 只具有简单的一些概念,但是我觉得要真正的在实际项目中可以灵活的使用,还是需要深入思考,做个好梦
新闻热点
疑难解答