C#匿名方法和Lambda表达式
当一个调用者想监听传来的事件的时候,它必须定义一个唯一的与相关委托签名匹配的方法。
在事件注册时直接将一个委托与一段代码相关联,这种代码叫做匿名方法。
namespace ConsoleApplication1 { class Program { public class Car { // 属性 public string CarName { get; set; } public int CurrentSpeed { get; set; } public int MaxSpeed { get; set; } // 成员 private bool carIsBroken; // 构造函数 public Car() { MaxSpeed = 180; } public Car(string name, int maxSpd, int curSpd) { CarName = name; CurrentSpeed = curSpd; MaxSpeed = maxSpd; //carIsBroken = false; } // 创建一个委托用于对Car事件的响应处理。 //public delegate void CarEngineHandler(string msg); public delegate void CarEngineHandler(object sender, CarEventArgs e); // Car类可以发送的事件 public event CarEngineHandler eCarIsBroken; public event CarEngineHandler eOverSpeedAlarm; public void Accelerate(int delta) { // 如果汽车已坏,触发eCarIsBroken事件 if (carIsBroken) { if (eCarIsBroken != null) // 触发事件! { //eCarIsBroken("Car is broken,can't drive now!"); eCarIsBroken(this,new CarEventArgs("Car is broken,can't drive now!")); } } else { CurrentSpeed += delta; } // 超速提醒 if (20 == MaxSpeed - CurrentSpeed && eCarIsBroken != null) // 触发事件! { //eOverSpeedAlarm("Alarm: Going too fast, drive slowly!"); eOverSpeedAlarm(this,new CarEventArgs("Alarm: Going too fast, drive slowly!")); } if (CurrentSpeed >= MaxSpeed) { carIsBroken = true; } else { Console.WriteLine("CurrentSpeed = {0}", CurrentSpeed); } } } // 利用EventArgs的派生类,来传递数据。 public class CarEventArgs : EventArgs { public readonly string msg; public CarEventArgs(string message) { msg = message; } } public static void TheCarIsBroken(string msg) { Console.WriteLine(msg); } static void Main(string[] args) { Car myCar = new Car("Audio Q5", 200, 60); // 采用匿名的方式注册事件处理程序, 匿名方法的最后需要有一个分号结束 myCar.eOverSpeedAlarm += delegate(object sender, CarEventArgs e) { Console.WriteLine("{0}:{1}", sender, e.msg); }; myCar.eCarIsBroken += delegate(object sender, CarEventArgs e) { Console.WriteLine("{0}:{1}", sender, e.msg); }; for (int i = 0; i < 12; i++) { myCar.Accelerate(20); } Console.ReadLine(); } } }
Lambda表达式是匿名方法的简单表达方式,从而彻底的简化了对委托的使用。
Lambada表达式是这样编写的:
首先定义一个参数列表,随后加上“=>"标记,然后加上处理这些参数的语句。
Lambda表达式的参数可以使显示类型化,也可以使隐式类型化的。
举例说明如下:利用泛型List<T>的FindAll()方法从一组数据中找出所有的偶数。
方法一:使用传统的委托方法
namespace ConsoleApplication1 { class Program { static void TraditionalDelegate() { // 创建整数列表 List<int> myList = new List<int> { }; myList.AddRange(new int[]{ 1, 2, 3, 4, 5, 9, 10, 21, 30, 68 }); // 使用传统泛型委托语法调用FindAll Predicate<int> callback = new Predicate<int>(IsEvenNumber); List<int> evenNumbers = myList.FindAll(callback); // 输出结果 foreach( int evenNumber in evenNumbers) { Console.WriteLine("{0},",evenNumber); } } // Predicate 委托的目标方法 static bool IsEvenNumber(int number) { return (0 == number % 2 ? true : false); } static void Main(string[] args) { TraditionalDelegate(); Console.ReadLine(); } }
方法二:使用匿名方法:
// 使用传匿名委托语法调用FindAll List<int> evenNumbers = myList.FindAll( delegate(int i) { return 0 == i % 2; });
方法三:采用Lambda表达式
// 使用Lambda表达式 List<int> evenNumbers = myList.FindAll(
i => 0 == (i % 2) );
至此,我们用Lambda表达式来更新之前写的Car 事件
static void Main(string[] args) { Car myCar = new Car("Audio Q5", 200, 60); // 使用Lambda表达式来挂起事件 myCar.eOverSpeedAlarm += (sender, e) => { Console.WriteLine(e.msg); }; myCar.eCarIsBroken += (sender, e) => { Console.WriteLine(e.msg); }; for (int i = 0; i < 12; i++) { myCar.Accelerate(20); } Console.ReadLine(); }
总结如下:
1. delegate 关键字间接的构造了一个派生自MuticastDelegate的类,委托对象保存一个方法列表。可以被同步调用(Invoke()),或异步调用(BeginInvoke()和EndInvoke())
2. event 关键字简化了事件发送到调用者的处理过程。
3. 匿名方法可以直接将一段代码与指定事件相关联。Lambda表达式是匿名方法的简化表达方式。