1、回调函数
回调函数实际上是方法调用的指针,又称函数指针。.NET以委托的形式实现了函数指针的概念。
但与C函数指针不同的地方在于:.NET委托是类型安全的。
.NET中的方法依托于类实例。所以不能直接将方法作为参数传递。而如果要传递方法,必须把方法封装在委托对象中,委托对象一般简称为委托。委托包含了方法细节信息。
2、声明委托
delegate void VoidOperation(uint x);
委托实现派生自System.MulticastDelegate,而System.MulticastDelegate又派生自System.Delegate。
3、使用委托
private delegate string GetAString(); int x = 40; GetAString gas = x.ToString; // 或者 GetAString gas = new GetAString(x.ToString); gas(); // ToString()方法无参数,所以直接调用即可,返回 40
C#语法中,委托总包含一个带一个参数的构造函数,这个参数就是委托引用的方法。且这个方法必须匹配最初定义的委托的签名。
方法可以是实例方法,也可以是静态方法。注意上面的参数是x.ToString,而不是x.ToString(),后者表示方法执行的结果,前者才表示该方法。
4、匿名方法
委托还有另外一种方式,将匿名方法传为委托的参数,如下:
private delegate string GetAString(string s); GetAString gas = delegate(string param) { string s = "hello, " + param; return s; }; gas("feichexia"); // 返回 hello, feichexia
匿名方法的优点是减少了系统开销,方法仅在委托使用时才定义。且能减少代码复杂度。
另外注意不要在匿名方法中使用跳转语句跳转到匿名方法外部,反之亦然。匿名方法内部不能访问外部的ref和out参数
5、委托版本冒泡排序
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace MyOnlineStore.DAC.Test { public delegate bool CompareOp(object op1, object op2); public class Employee { private string _name; private decimal _salary; public Employee(string name, decimal salary) { this._name = name; this._salary = salary; } public override string ToString() { return string.Format(_name + ", {0:C}", _salary); } public static bool IsGreater(object obj1, object obj2) { Employee emp1 = (Employee) obj1; Employee emp2 = (Employee) obj2; return (emp1._salary>emp2._salary); } } public class BubbleSort { public static void Sort(object[] array, CompareOp gtMethod) { for (int i = 0; i < array.Length; i++) { for (int j = i + 1; j < array.Length; j++) { if (gtMethod(array[j], array[i])) { object temp = array[i]; array[i] = array[j]; array[j] = temp; } } } } public static void main() { Employee[] emps = { new Employee("Bug", 20000), new Employee("Diary", 1000), new Employee("June", 12132), new Employee("July", 12300) }; CompareOp compOp = Employee.IsGreater; BubbleSort.Sort(emps, compOp); } } }
6、多播委托
一个委托可以包含多个方法,如下:
delegate void CaculateOp(double val); CaculateOp ops = MathOperations.MultiplyByTwo; ops += MathOperations.DivideByTwo; 等价于 delegate void CaculateOp(double val); CaculateOp op1 = MathOperations.MultiplyByTwo; CaculateOp op2 = MathOperations.DivideByTwo; CaculateOp ops = op1 + op2;
多播委托可以识别 + += - -=(-和-=用于删除方法调用)
7、事件
btnOne.Click = new EventHandler(Button_Click);
EventHandler实际上是委托类型,如下:
public delegate void EventHandler(object sender, EventArgs e); // sender是引发事件的对象,e包含事件有关信息
所以Button_Click的方法签名也必须与此一致。可以为一个事件绑定多个事件处理方法,如下:
btnOne.Click = new EventHandler(Button_Click); btnOne.Click += new EventHandler(Button_Click_2);
8、...