C#中的委托、事件以及lambda表达式是经常让我头晕的内容,今天简单总结一下,内容来自《C#入门经典》13、14章。
委托(delegate)就是一种可以把引用存储为函数的类型,实际上非常简单。首先定义一个委托,然后就可以声明委托类型的变量,然后可以把该变量初始化为与委托具有相同返回类型和参数列表的函数的引用。之后就可以使用委托变量调用函数,就像该变量是一个函数一样。
匿名方法(anonymous method):并非传统意义上的方法,而是纯粹作为委托目的而创建的。格式如下:
delegate(parameters){//anonymous method code}
事件(event):事件类似于异常,因为他们都是由对象引发(抛出),但是区别是不是使用try--catch类似的结构来处理事件,而是必须订阅(subscribe)他们,订阅一个事件的含义是提供在事件发生时执行的代码,他们被称为事件处理程序。对事件处理程序的要求是必须匹配事件所要求的返回类型和参数,这些限制是事件定义的一部分,由一个委托指定。
处理过程如下:应用程序创建一个可以引发事件的对象,然后应用程序订阅该事件,然后事件发生后,通知事件处理程序。
1 //PRogram类 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace testEvent02 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 Connection myConnection1 = new Connection(); 15 myConnection1.name = "first"; 16 Connection myConnection2 = new Connection(); 17 myConnection2.name = "second"; 18 Display myDisplay = new Display(); 19 //MessageArrived事件订阅的处理方法是DisplayMessage 20 myConnection1.MessageArrived += new MessageHandler(myDisplay.DisplayMessage); 21 myConnection2.MessageArrived += new MessageHandler(myDisplay.DisplayMessage); 22 myConnection1.Connect(); 23 myConnection2.Connect(); 24 Console.ReadKey(); 25 } 26 } 27 } 28 29 //Connection类 30 using System; 31 using System.Collections.Generic; 32 using System.Linq; 33 using System.Text; 34 using System.Threading.Tasks; 35 using System.Timers; 36 37 namespace testEvent02 38 { 39 //首先定义委托 40 public delegate void MessageHandler(Connection source, MessageArrivedEventArgs e); 41 public class Connection 42 { 43 //根据委托,定义事件 44 public event MessageHandler MessageArrived; 45 public string name { get; set; } 46 private Timer poolTimer; 47 48 public Connection() 49 { 50 poolTimer = new Timer(500); 51 poolTimer.Elapsed += new ElapsedEventHandler(checkForMessage); 52 } 53 54 public void Connect() 55 { 56 poolTimer.Start(); 57 } 58 59 public void Disconnect() 60 { 61 poolTimer.Stop(); 62 } 63 64 private static Random random = new Random(); 65 private void checkForMessage(object source, ElapsedEventArgs e) 66 { 67 Console.WriteLine("checking for new message"); 68 if ((random.Next(9) == 0) && (MessageArrived != null)) 69 //引发MessageArrived事件,注意参数 70 MessageArrived(this, new MessageArrivedEventArgs("hello")); 71 } 72 } 73 } 74 //Display类 75 using System; 76 using System.Collections.Generic; 77 using System.Linq; 78 using System.Text; 79 using System.Threading.Tasks; 80 81 namespace testEvent02 82 { 83 class Display 84 { 85 public void DisplayMessage(Connection source, MessageArrivedEventArgs e) 86 { 87 Console.WriteLine("message arrived from : {0}", source.name); 88 Console.WriteLine("message text : {0}", e.Message); 89 } 90 } 91 } 92 //MessageArrivedEventArgs类 93 using System; 94 using System.Collections.Generic; 95 using System.Linq; 96 using System.Text; 97 using System.Threading.Tasks; 98 99 namespace testEvent02100 {101 public class MessageArrivedEventArgs102 {103 //可以传递的参数104 private string message;105 public string Message { get { return message; } }106 public MessageArrivedEventArgs() { message = "no message sent"; }107 public MessageArrivedEventArgs(string newmessage) { message = newmessage; }108 }109 }View Code
其中,MessageHandler委托中包含了事件处理程序中常见的两种参数:(object source, MessageArrivedEventArgs e);分别是:引发事件的对象的引用,以及由事件传送的参数。
由于委托用起来比较麻烦,需要先定义委托,声明委托变量,然后把该变量初始化为与委托具有相同返回类型和参数列表的函数的引用,然后使用委托变量调用函数,所以微软就定义了一个简单方法,就是Action<T>委托和Func<T>委托,分别代表有/无返还值的情况,用法如下:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace test_lambda01 8 { 9 class Program10 {11 public delegate void myprint(String s);12 static void Main(string[] args) {13 name myname = new name();14 myprint print1 = myname.print2;15 print1("print1111");16 17 Action<String> print2 = myname.print2;18 print2("print2222 ");19 20 myprint print3 = delegate(String s) { Console.WriteLine("{0}", s); }; //内联的匿名方法21 print3("print3333 ");22 23 Console.ReadKey();24 }25 }26 }27 //name类28 using System;29 using System.Collections.Generic;30 using System.Linq;31 using System.Text;32 using System.Threading.Tasks;33 34 namespace test_lambda0135 {36 class name37 {38 public name(){}39 public name(String s) { Console.WriteLine(s); }40 public void print1() { Console.WriteLine("print1"); }41 public void print2(String s) { Console.WriteLine("{0}", s); }42 }43 }View Code
这里面的三种写法,效果是相同的。
lambda表达式
我理解:lambda表达式本质上就是一个委托,用于简化C#编程的某些方面,由3部分组成:放在括号中的参数列表;=>运算符;C#语句。编译器会提取这个lambda表达式,创建一个匿名方法。
如以下语句的效果同上面三种写法。
Action<String> newprint = (s) => { Console.WriteLine("{0}", s); };
注意有些函数就是用Action<T>委托和Func<T>委托作为参数的,使用起来非常方便,如在List中查找第一个名为"Jim"的人:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace delegate02 8 { 9 class Program10 {11 delegate bool mydelegate(Employee);12 static void Main(string[] args)13 {14 List<Employee> noEmployees = new List<Employee>();15 16 List<Employee> oneEmployeeList = new List<Employee> { 17 new Employee {ID = 55, Name = "Sussie Queue", Salary = 6000}18 };19 20 List<Employee> employees = new List<Employee>{21 new Employee { ID = 1, Name = "Jim Smith", Salary = 12345.50 },22 23 new Employee { ID = 7, Name = "Jane Doe", Salary = 31234.50 },24 25 new Employee { ID = 9, Name = "John Doe", Salary = 13923.99 },26 27 new Employee { ID = 13, Name = "Jim Smith", Salary = 30123.49 }28 };29 30 var first = employees.First();31 32 33 //firstJim和firstJim1的效果相同34 var firstJim = employees.First(e => e.Name.StartsWith("Jim"));35 var firstJim1 = employees.First(delegate(Employee em) { return em.Name.StartsWith("Jim"); });36 37 var firstDoe = employee
新闻热点
疑难解答