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
新聞熱點
疑難解答