委托:
C# 中的委托类似于 C 或 C++ 中的函数指针。使用委托使程序员可以将方法引用封装在委托对象内。然后可以将该委托对象传递给可调用所引用方法的代码,而不必在编译时知道将调用哪个方法。与 C 或 C++ 中的函数指针不同,委托是面向对象、类型安全的,并且是安全的。
委托声明定义一种类型,它用一组特定的参数以及返回类型封装方法。对于静态方法,委托对象封装要调用的方法。对于实例方法,委托对象同时封装一个实例和该实例上的一个方法。如果您有一个委托对象和一组适当的参数,则可以用这些参数调用该委托。
委托的一个有趣且有用的属性是,它不知道或不关心自己引用的对象的类。任何对象都可以;只是方法的参数类型和返回类型必须与委托的参数类型和返回类型相匹配。这使得委托完全适合“匿名”调用。
简单例子如下:
class BuyTicket{
public static void buyTicket()
{
Console.WriteLine("嗨,又要去排队买火车票");
}
public static void buyMovieTicket()
{
Console.WriteLine("泡妞,买电影票还让我买!");
}
}
class Program
{
public delegate void BuyTicketEventHandler();//这个就是委托,委托以delegate为关键字,void的为返回类型,BuyTicketEventHandler为委托名,括号中为委托
static void Main(string[] args)
{
BuyTicketEventHandler myDelegate = new BuyTicketEventHandler(BuyTicket.buyTicket);
myDelegate += BuyTicket.buyMovieTicket;
myDelegate();
Console.ReadKey();
}
}
以上是一个纯委托的例子。
委托和事件:
事件编程可以分成两部分类:事件发生的类(发布者)和事件接收处理的类(订阅者)。事件发生的类就是说在这个类中触发了一个事件,但这个类并不知道哪个对象或方法将会接收到并处理它触发的事件。所需要的是在发送方和接收方之间存在一个媒介。这个媒介在.NET Framework中就是委托(delegate)。在事件接收处理的类中,我们需要有一个处理事件的方法。
实例一展示了事件和委托实现杂志发布和订阅的过程。只有有订阅者订阅的时候(如果有对象注册),才能调用发布者发布的事件。订阅者类中方法要和委托有着相同的返回值和相同的参数。
实例一如下:
//所有订阅者感兴趣的对象,也就是e,都要继承微软的EventArgs
public class PubEventArgs:EventArgs
{
public readonly string magazineName;
public PubEventArgs()
{
}
public PubEventArgs(string magazineName)
{ this.magazineName = magazineName;}
}
//发布者
public class Publisher
{
public delegate void PublishEventHandler(Object sender, PubEventArgs e);
public event PublishEventHandler Publish;
protected virtual void OnPublish(PubEventArgs e)
{
if (Publish != null)
{
this.Publish(this, e);
}
}
public void issue(string magazineName)
{
OnPublish(new PubEventArgs(magazineName));
}
}
//订阅者
public class Subscriber1
{
public static void Recv1(Object sender,PubEventArgs e)
{
Console.WriteLine("haha,我已经收到第一期的《"+e.magazineName+"》了");
}
}
public class Subscriber2
{
public static void Recv2(Object sender, PubEventArgs e)
{
Console.WriteLine("幼稚,这么大了,还看《西游记》!");
Console.WriteLine("这个我定的《" + e.magazineName + "》!");
}
}
class Program
{
static void Main(string[] args)
{
Publisher pub = new Publisher();
Console.Write("请选择要发行的杂志:\n1、西游记\n2、走遍美国\n");
string name = Console.ReadLine();
switch (name.Trim())
{
case "1":
pub.Publish += new Publisher.PublishEventHandler(Subscriber1.Recv1);
pub.issue("西游记");
break;
case "2":
pub.Publish += Subscriber2.Recv2;
pub.issue("走遍美国");
break;
default:
break;
}
Console.ReadKey();
}
}
运行结果:
其中,
public delegate void PublishEventHandler(Object sender, PubEventArgs e);//定义代理,返回值为void,参数为sender对象和订阅者感兴趣的对象类PubEvent,这个类需要继承EventArgs类,如果没有需要传的参数,则可以直接为EventArgs。
public event PublishEventHandler Publish;//定义代理的事件Publish
pub.Publish += new Publisher.PublishEventHandler(Subscriber1.Recv1);和 pub.Publish += Subscriber2.Recv2;是事件调用的两种不同的方法。
事件调用必须为+= 或者-=。
实例二,相似的例子:
当温度大于90,并且有对象注册的时候,触发事件。并且提示显示信息和报警。
//温度类
public class Heart
{
private int temperature;
public delegate void BoidWaterEventHandler(int param);
public event BoidWaterEventHandler BoidWater;
public void Boid()
{
for (int i = 0; i < 100;i++ )
{
temperature = i;
if (temperature > 90&& BoidWater != null) //当温度大于90,并且有对象注册的时候
{
BoidWater(temperature);
}
}
}
}
//显示类
public class Displayer
{
public void ShowTemperature(int temperature)
{
Console.WriteLine("Display:水快烧开了,温度为{0}",temperature);
}
}
//警报类
public class Alarmer
{
public static void AlarmLoud(int temperature)
{
Console.WriteLine("Alarm:警报响,水的温度到达{0}", temperature);
}
}
class Program
{
static void Main(string[] args)
{
Heart heart = new Heart();
Displayer disp = new Displayer();
heart.BoidWater +=(new Displayer()).ShowTemperature;
heart.BoidWater += disp.ShowTemperature;
heart.BoidWater += Alarmer.AlarmLoud;
heart.Boid();
Console.ReadKey();
}
}
运行结果:
参考文档
1、《c#中的委托和事件》 http://www.cnblogs.com/JimmyZhang/archive/2011/12/25/903360.html
2、《大白话系列之c#委托和事件讲解》 http://www.cnblogs.com/wudiwushen/archive/2010/04/20/1698795.html