回调函数是一种非常有用的编程机制,它的存在已经有很多年了。.NET通过委托来提供回调函数机制。不同于其他平台(比如非托管C++)的回调机制,委托的功能要多得多。例如,委托确保回调方法是类型安全的(这是clr最重要的目标之一)。委托还允许顺序调用多个方法,并支持调用静态方法和实例方法。
初识委托
c“运行时”的qsort函数获取指向一个回调函数的指针,一遍对数组中的元素进行排序。在windows中,窗口过程、钩子过程和异步过程调用等都需要回调函数。.net framework中,回调方法的应用更是广泛。例如,可以登记回调方法来获取各种各样的通知,例如未处理的异常、窗口状态变化、菜单项选择、文件系统变化、窗体控制事件和异步操作已完成等。
在非托管C/C++中,非成员函数的地址只是一个内存地址。这个地址不携带任何额外信息,。比如函数期望收到的参数个数、参数类型、函数返回值类型以及函数调用协定。简单地说,非托管C/C++回调函数不是类型安全的(不过他们确实是一种非常轻量级的机制)。
.NET的回调函数和非托管windows编程环境的回调函数一样有用,一样普遍。但是,.net提供了称为委托的类型安全机制。为了理解委托,先来看看如何使用它。
委托4个最基本的步骤:
1)定义委托类型
2)有一个方法包含要执行的代码(签名要与委托相同)
3)创建一个委托实例化(包含声明委托对象)
4)执行调用(invoke)委托实例
具体解释如下:
1.定义委托类型
委托类型就是参数类型的一个列表以及一个返回类型。
delegate void StringProcessor(string input);
其中的StringProcessor是一个类型。
2.定义签名相同的方法
定义的方法要与委托有类型相同的返回值和参数。
private void GetStringLength(object x){} //C#2.0以后认为一致
3.创建委托实例
创建委托实例就是指定在调用委托实例时执行的方法。
StringProcessor proc1,proc2 //GetStringLength 实例方法 proc1= new StringProcessor(GetStringLength); //GetString 静态方法 proc2 += GetString;
4.调用委托
调用委托就是调用一个委托实例方法。
proc1("Hello World");
以下代码演示了如何声明、创建和使用委托。
// 1.声明委托类型 internal delegate void Feedback(Int32 value); internal class Program { private static void Main(string[] args) { StaticDelegateDemo(); InstanceDelegateDemo(); ChainDelegateDemo1(new Program()); ChainDelegateDemo2(new Program()); } private static void StaticDelegateDemo() { Console.WriteLine("----- Static Delegate Demo -----"); Counter(1, 3, null); // 3.创建委托实例 Counter(1, 3, new Feedback(Program.FeedbackToConsole)); Counter(1, 3, new Feedback(FeedbackToMsgBox)); Console.WriteLine(); } private static void InstanceDelegateDemo() { Console.WriteLine("----- Instance Delegate Demo -----"); Program di = new Program(); // 3.创建委托实例 Counter(1, 3, new Feedback(di.FeedbackToFile)); Console.WriteLine(); } private static void ChainDelegateDemo1(Program di) { Console.WriteLine("----- Chain Delegate Demo 1 -----"); // 3.创建委托实例 Feedback fb1 = new Feedback(FeedbackToConsole); Feedback fb2 = new Feedback(FeedbackToMsgBox); Feedback fb3 = new Feedback(di.FeedbackToFile); Feedback fbChain = null; fbChain = (Feedback)Delegate.Combine(fbChain, fb1); fbChain = (Feedback)Delegate.Combine(fbChain, fb2); fbChain = (Feedback)Delegate.Combine(fbChain, fb3); Counter(1, 2, fbChain); Console.WriteLine(); fbChain = (Feedback)Delegate.Remove(fbChain, new Feedback(FeedbackToMsgBox)); Counter(1, 2, fbChain); } private static void ChainDelegateDemo2(Program di) { Console.WriteLine("----- Chain Delegate Demo 2 -----"); Feedback fb1 = new Feedback(FeedbackToConsole); Feedback fb2 = new Feedback(FeedbackToMsgBox); Feedback fb3 = new Feedback(di.FeedbackToFile); Feedback fbChain = null; fbChain += fb1; fbChain += fb2; fbChain += fb3; Counter(1, 2, fbChain); Console.WriteLine(); fbChain -= new Feedback(FeedbackToMsgBox); Counter(1, 2, fbChain); } private static void Counter(Int32 from, Int32 to, Feedback fb) { for (Int32 val = from; val <= to; val++) { // 如果指定了任何回调,就可以调用它 if (fb != null) // 4.调用委托 fb(val); } } // 2.声明签名相同的方法 private static void FeedbackToConsole(Int32 value) { Console.WriteLine("Item=" + value); } // 2.声明签名相同的方法 private static void FeedbackToMsgBox(Int32 value) { Console.WriteLine("Item=" + value); } // 2.声明签名相同的方法 private void FeedbackToFile(Int32 value) { StreamWriter sw = new StreamWriter("Status", true); sw.WriteLine("Item=" + value); sw.Close(); } }