C#委托、事件和Lambda表达式(1)
1.委托的定义
从本质上讲,委托是一个类型安全的对象,它指向程序中另一个或多个以后会被调用的方法。说白了委托就是实现程序或内存中两个实体的双向通信。
创建一个委托类型时使用delegate关键字,委托名称可自由定义但所定义的委托必须匹配它所指向的方法
2.一个简单的例子
新建一个CarDelegat的控制台应用程序,并定义如下所示的Car类:
1 public class Car 2 { 3 public int CurrentSpeed { get; set; } 4 public int MaxSpeed { get; set; } 5 public string PetName { get; set; } 6 7 private bool carIsDead; 8 public Car() 9 { 10 MaxSpeed = 100; 11 } 12 public Car(string name,int maxSp,int currSp) 13 { 14 CurrentSpeed = currSp; 15 MaxSpeed = maxSp; 16 PetName = name; 17 } 18 //定义委托类型 19 public delegate void CarEngineHandler(string msgForCaller);
//定义每个委托类型的成员变量 20 private CarEngineHandler listOfHandler;
//向调用者添加注册函数 21 public void RegisterWithCarEngine(CarEngineHandler methodToCall) 22 { 23 listOfHandler = methodToCall; 24 } 25 //Accelerate方法在某些情况下调用委托的调用列表,如果汽车不能用了触发引爆事件 26 public void Accelerate(int delta) 27 { 28 if (carIsDead) 29 { 30 if (listOfHandler!=null) 31 { 32 listOfHandler("Sorry, this car is dead ...");//调用委托的调用列表 33 } 34 } 35 else 36 { 37 CurrentSpeed += delta; 38 if (10==(MaxSpeed-CurrentSpeed)&&listOfHandler!=null) 39 { 40 listOfHandler("Careful buddy! Gonna blow!");//调用委托的调用列表 41 } 42 43 if (CurrentSpeed>=MaxSpeed) 44 { 45 carIsDead = true; 46 } 47 else 48 { 49 Console.WriteLine("CurrentSpeed={0}", CurrentSpeed); 50 } 51 } 52 } 53 }
Program类代码如下:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Console.WriteLine("*******************");
//首先,创建一个car对象 6 Car c1 = new Car("SlugBug", 100, 10);
//现在,告诉汽车,他想要向我们(调用者)发送信息时使用哪个方法 7 c1.RegisterWithCarEngine(new Car.CarEngineHandler(OnCarEngineEvent));
//加速,以此来触发事件
10 Console.WriteLine("******** Speeding Up ****"); 11 for (int i = 0; i < 6; i++) 12 { 13 c1.Accelerate(20); 14 15 } 16 Console.ReadKey(); 17 }
//要传入事件的方法(与相关委托完全匹配,包括string类型的参数和void返回类型) 18 private static void OnCarEngineEvent(string msgForCaller) 19 { 20 Console.WriteLine("\n **** Message From Car Object ****"); 21 Console.WriteLine("=>{0}",msgForCaller); 22 Console.WriteLine("***********************************\n"); 23 } 24 }
3.支持多路广播
一个委托对象可以维护一个可调用方法的列表而不是单独一个方法。给委托对象添加多个方法时,不用直接分配,重载+=操作符即可
修改Car类如下:
1 public void RegisterWithCarEngine(CarEngineHandler methodToCall) 2 { 3 listOfHandler += methodToCall; 4 }
对委托对象使用+=操作符时,调用者就可以为同样的回调注册多个目标对象了
如下可以在Main函数中增加如下代码
//多注册一个目标
c1.RegisterWithCarEngine(new Car.CarEngineHandler(OnCarEngineEvent2));
//委托所指向的方法 private static void OnCarEngineEvent2(string msgForCaller) { Console.WriteLine("================================"); Console.WriteLine("-->{0}",msgForCaller.ToUpper()); }
当然也可以使用-=操作符从委托的调用列表中移除成员。这样调用者就可以在运行时简单的退订某个已知的通知
可以在Car类中增加如下方法
public void UnRegisterWithCarEngine(CarEngineHandler methodToCall) { listOfHandlers -= methodToCall; }
Main方法中使用如下:
//先绑定委托对象,然后在注销 Car.CarEngineHandler handler2 = new Car.CarEngineHandler(OnCarEngineEvent2); c1.RegisterWithCarEngine(handler2); //其它逻辑不动 ...... ...... //注销第二个处理程序 c1.UnRegisterWithCarEngine(handler2);
4.方法组转换语法
为了简化操作,C#提供了一种叫方法组转换的简便方法。该特性允许我们在调用以委托作为参数的方法时直接提供方法的名称 ,而不用创建委托对象
c1.RegisterWithCarEngine(CallMeHere); private static void CallMeHere(string msgForCaller) { Console.WriteLine("\n ################"); Console.WriteLine("->> Message form car : {0}",msgForCaller); }
这里我们没有直接分配相关的委托对象,而是简单的指定了与委托期望的签名相匹配的方法