C#中的委托和事件
1 委托
委托是寻址方法的.NET版本。它在功能上与C++中的函数指针类似,但是函数指针不是类型安全的,因为无法判断这个指针实际上是指向什么,参数和返回类型也不知道。而委托则是类型安全的类,它定义了返回类型和参数的类型。委托类既可以引用一个方法,也可以引用多个方法。
我们用书上的一个例子来看如何使用委托。
先是定义一个类MathOperations,它有两个静态方法,对double类型的值执行两个操作。
using System; namespace LearnDelegate { public class MathOperations { public MathOperations () { } public static double MultiplyByTwo(double value) { return value * 2; } public static double Square(double value) { return value * value; } } }
然后使用委托调用这些方法。
using System; namespace LearnDelegate { delegate double DoubleOp(double x); class MainClass { public static void Main (string[] args) { Console.WriteLine ("Learn Delegate!"); DoubleOp[] operations = { MathOperations.MultiplyByTwo, MathOperations.Square }; for(int i=0;i<operations.Length;i++) { Console.WriteLine ("Using operations[{0}]:",i); ProcessAndDisplayNumber (operations[i],2.0); ProcessAndDisplayNumber (operations[i],7.94); ProcessAndDisplayNumber (operations[i],1.414); Console.WriteLine (); } } static void ProcessAndDisplayNumber(DoubleOp action, double value) { double result = action (value); Console.WriteLine ("Value is {0}, result of operation is {1}",value,result); } } }
运行结果如下:
2 事件
事件基于委托,为委托提供了一种发布/订阅机制。
2.1 事件发布程序
从CarDealer类开始,它基于事件提供一个订阅。CarDealer类用event关键字定义了类型为EventHandler<CarInfoEventArgs> 的NewInfo事件。在NewCar()中,通过调用RaiseNewCarInfo方法触发NewCarInfo事件。这个方法实现了检查委托是否为空,如果不为空,就引发事件。
using System; namespace LearnEvent { public class CarInfoEventArgs: EventArgs { public CarInfoEventArgs (string car) { this.Car = car; } public string Car{ get; private set;} } public class CarDealer { public event EventHandler<CarInfoEventArgs> NewCarInfo; public void NewCar(string car) { Console.WriteLine("CarDealer, new car {0}", car); RaiseNewCarInfo(car); } protected virtual void RaiseNewCarInfo(string car) { EventHandler<CarInfoEventArgs> newCarInfo = NewCarInfo; if (newCarInfo != null) { newCarInfo (this, new CarInfoEventArgs(car)); } } } }
2.2 事件侦听器
Consumer类用作事件侦听器。这个类订阅了CarDealer类的事件,并且定义了NewCarIsHere方法,该方法满足EventHandler<CarInfoEventArgs>委托的要求,参数类型是object和CarInfoEventArgs。
using System; namespace LearnEvent { public class Consumer { private string name; public Consumer (string name) { this.name = name; } public void NewCarIsHere(object sender, CarInfoEventArgs e) { Console.WriteLine ("{0}: car {1} is new",name,e.Car); } } }
现在来连接事件发布程序和订阅器。
using System; namespace LearnEvent { class MainClass { public static void Main (string[] args) { //Console.WriteLine ("Hello World!"); var dealer = new CarDealer(); var michael = new Consumer ("Michael"); dealer.NewCarInfo += michael.NewCarIsHere; dealer.NewCar ("MAZDA"); Console.WriteLine (); var sebastian = new Consumer ("Sebastian"); dealer.NewCarInfo += sebastian.NewCarIsHere; dealer.NewCar ("BMW"); Console.WriteLine (); dealer.NewCarInfo -= michael.NewCarIsHere; dealer.NewCar ("Benz"); Console.WriteLine (); } } }
运行结果如下: