5、委托的理解
1:委托是一种存储函数引用的类型
2:使用delegate关键字定义委托,同时声明返回类型和参数列表。
namespace test { class Program { //定义一个委托 delegate double ProcessEvent(double p1, double p2); //委托变量 static ProcessEvent process; static double Add(double p1, double p2) => p1 + p2; static double Subtract(double p1, double p2) => p1 - p2; static void Main(string[] args) { Console.WriteLine("Enter 2 numbers:"); string line = ReadLine(); int pos = line.IndexOf(','); double p1 = ToDouble(line.Substring(0,pos)); double p2 = ToDouble(line.Substring(pos+1, line.Length - pos - 1)); Console.WriteLine("Enter type:"); line = Console.ReadLine(); if(line == "a") { //将函数引用赋给委托变量(初始化与委托有相同返回值和参数列表的函数引用.就可以通过该委托变量调用这个函数) process += new ProcessEvent(Add); } else { process += new ProcessEvent(Subtract); } //使用该委托调用选择的处理函数 WriteLine(process(p1, p2)); } } }
6、事件的处理
事件是.NET中最常用的OOP技术。事件类似异常,但是没有try-catch。事件的引发和订阅实际上就是一种委托,事件的处理方法的返回值和参数由委托指定。
C#中事件的编程分为两部分:事件触发、事件的订阅(处理)。而委托就是事件发生方和处理方之间的一个桥梁。
//申明委托类型 public delegate void KeyboardHandler(String input); //事件发布者 class Sender { //事件定义关键字 委托类型 事件名称 public event KeyboardHandler Keydown; public void Run() { while (true) { string line = ReadLine(); //触发事件 Keydown(line); } } } //事件订阅者(多个订阅者可同时订阅一个事件) class Process { public Process(Sender sender) { //事件的注册(+=将处理程序挂载到事件,-=表示事件卸载处理程序,可添加多个处理函数) sender.Keydown += new KeyboardHandler(OnKeyDown); } //真正的事件处理函数 private void OnKeyDown(String input) { WriteLine("Ascii code of Char " + input + " is:" + (short)(input[0])); } } class Start { static void Main(string[] args) { //实例化事件发送器 Sender sender = new Sender(); //实例化事件处理器 Process process = new Process(sender); //启动运行 sender.Run(); } }
事件注册的具体格式如下:
sender.Keydown += new KeyboardHandler(OnKeyDown);
事件 += new 委托类型(方法标识符);
即如果触发sender对象的Keydown事件,就调用OnKeyDown方法来处理,传递给OnKeyDown的参数取决于委托类型KeyboardHandler定义的参数。
事件的注册还有一种更简洁方式
sender.Keydown += OnKeyDown;
运行结果
7、Lambda表达式
(未类型化的参数列表)=>C#语句
=>是运算符
上面事件的注册可以用匿名方法或Lambda表达式来改造
public Process(Sender sender) { //事件的注册 sender.Keydown += new KeyboardHandler(OnKeyDown); } //真正的事件处理函数 private void OnKeyDown(String input) { WriteLine("Ascii code of Char " + input + " is:" + (short)(input[0])); }
用匿名方法改造
public Process(Sender sender) { sender.Keydown += delegate(string input) { WriteLine("Ascii code of Char " + input + " is:" + (short)(input[0])); }; }
可以看出OnKeyDown处理函数通过匿名方法形式,对其他应用程序来说是隐藏的,也就是说无法重用这个事件处理函数。
需要注意的一点,匿名方法和委托类型的定义都用到了delegate关键字。
Lambda表达式用于匿名方法
public Process(Sender sender) { //lambda表达式注册及处理事件 sender.Keydown += (input)=> WriteLine("Ascii code of Char " + input + " is:" + (short)(input[0])); }
实际上,编译器在提取Lambda表达式时,会创建一个匿名方法。Lambda表达式的参数实际就是用到了前面所说的类型推断来确定参数的类型,也可以指定参数类型。Lambda表达式也可以执行多个语句,可以有返回值。
(param1...paramN) => { //语句1 //语句2 return value; }
附录一
快捷键
F5:跳转到下一断点
F10:单步调试
“Ctrl + -” : 返回到上一个光标处
“Ctrl + Shift + - ”:前进到下一个光标位置
····