委托入门(第二章)
使用委托改造Car类型
- 定义将通知发送给调用者的委托类型。
- 声明Car类中每个委托类型的成员变量
- 在Car上创建辅助函数使调用者能够指定由委托成员变量保存的方法
- 修改Accelerate()方法以适当的情形下调用委托的调用列表。
public calss Car { //定义委托变量 public delegate void AboutToBlow(string msg); public delegate void Exploded(string msg); //定义每个委托类型的成员变量 private AboutToBlow almostDeadList; private Exploded explodedList; //使用辅助方法向调用列表添加成员 public void OnAboutToBlow(AboutToBlow clientMethod) { almostDeadList=clientMethod; } public void OnExploded(Exploded clientMethod) { explodedList=clientMethod; } ... }
我们直接在Car类型作用域定义委托类型。实际上我们在Car类创建了两个嵌套的类(AboutToBlow和Exploded)
注意我们声明了两个私有成员变量(每个委托类型各一个)两个辅助函数,从而使客户端能给委托调用列表添加方法。
下面是调用委托:
public void Accelerate(int delta) { //如果汽车不能用了,触发引爆事件 if(carIsDead) { if(explodedList!=null) { explodedList("sorry,this card is dead..."); } } else { currSpeed+=delta; //快不能用了吗? if(10==maxSpeed-currSpeed&&almostDeadList!-null_ { almostDeadList("Careful boddy! Gonna blow!"); } //还好着呢 if(currSpeed>=maxSpeed) carIsDead=true; else Console.WriteLine("CurrSpeed={0}",currSpeed); } }
要注意调用almostDeadList和explodedList成员变量保存的方法之前要检查两个变理是否是空值。原因在于通过调用OnAboutToBlow()和OnExploded()分配这些对象是调用者的任务。如果调用者没有调用这些方法而我们试图调用委托调用列表,将在运行时触发一个引用为空异常并使程序失败。
class Program { static void main(string[] args) { Console.Write("####Delegates as events ####\n"); Car cl=new Car("SlugBug",100,10); cl.OnAboutToBlow(new Car.AboutToBlow(CarAboutToBlow)); cl.OnExploded(new Car.Exploded(CarExploded)); Console.WriteLine("Speed up"); for(int i=0;i<7;i++) cl.Accelerate(20); Console.ReadLine(); } public static void CarAboutToBlow(string msg) { Console.WriteLine(msg); } public static void CarExploded(stirng msg) { Console.WriteLine(msg);} }
多路广播
.net委托内置支持多路广播。即是说一个委托对象可以维护一个可调用方法的列表而不是一个方法。给一个托委对象添加多个方法时,不用直接分配,重载+=运算符即可。下面通过修改OnAboutToBlow()和OnExploded()方法说明:
public class Car { public void OnAboutToBlow(AboutToBlow clientMethod) { almostDeadList+=clientMethod;} public void OnExploded(Exploded clientMethod) { explodedList+=clientMethod} ... } 这样调用者就可以为同样的回调注册多个目标对象了: class program { static void Main(stirng[] args) { Console.WriteLine(Delegates as event enablers); Car cl=new Car{"SlugBug",100,10); //注册多个事件处理程序 cl.OnAboutToBlow(new Car.AboutToBlow(CarAboutToBlow)); cl.OnAboutToBlow(new Car.AboutToBlow(CarIsAlmostDoomed)); cl.OnExploded(new Car.Exploded(CarExploded); } //car调用它们 public static void CarAboutToBlow(stirng msg) { Console.WriteLine(msg);} public static void CarIsAlmostDoomed(stirng msg) { Console.WriteLine("Critical Message from Car:{0}",msg);} public static void CarExploded(stirng msg) { Console.WriteLine(msg);}
根据CIL可发现,+=实际上转换为一个对静态Delegate.Combline()方法的调用。如果调用者与AboutToBlow和Exploded通知断开,可给Car类型添加如下辅助方法:
public class Car
{
public void OnAboutToBlow(AboutToBlow clientMethod)
{ almostDeadList+=clientMethod;}
public void OnExploded(Exploded clientMethod)
{ explodedList+=clientMethod}
...
}