在大话设计模式中有一个模式叫做观察者模式,里面涉及到了委托和事件的使用。虽然在一开始学习C#的时候有接触过,但是还是很陌生,稳扎稳打,才能平步青云。所以让我们来熟悉吧!
何为委托?
委托是对函数的封装,可以当作给方法的特征指定一个名称。委托是一种引用方法的类型。一旦为委托分配了方法,委托将与该方法具有完全相同的行为。委托对象使用的关键字delegate来声明。通俗易懂的说,委托就是用来执行方法或者函数的一个东西。何为事件?
事件则是委托的一种特殊形式,当发生有意义的事情时,事件对象处理通知过程。事件是说在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。事件对象用event关键字声明。
下面结合实例来讲解两者的关系
class Program
{
static void Main(string[] args)
{
Cat cat=new Cat ("Tom");
Mouse mouse1=new Mouse ("Jerry");
Mouse mouse2=new Mouse("Jack");
cat.CatShout +=new Cat.CatShoutEventHandler(mouse1.Run );
cat .CatShout +=new Cat.CatShoutEventHandler (mouse2.Run );
//表示将Mouse的Run方法通过实例化委托Cat.CatShoutEventHandler登记到Cat事件CatShout当中。
cat.Shout ();
Console.Read ();
}
}
class Cat
{
private string name;
public Cat(string name)
{
this.name = name;
}
public delegate void CatShoutEventHandler();
//声明委托CatShoutEventHandle
public event CatShoutEventHandler CatShout;
//声明事件CatShout,它的事件类型是委托CatShoutEventHandler
public void Shout()
{
Console.WriteLine ("瞄,我是{0}。",name);
if (CatShout !=null )
{
CatShout ();
//表明当执行Shout()方法时,如果CatShout中有对象登记事件,则执行CatShout()
}
}
class Mouse
{
private string name;
public Mouse (string name)
{
this.name =name;
}
public void Run(object sender,CatShoutEventArge args)
{
Console.WriteLine ("老猫{0}来了,{1}快跑!",args.Name ,name );
}
}
在这个实例中CatShoutEventHandler属于委托,CatShout属于事件。
是否有点小疑问,Cat和Mouse是怎么联系起来的?
关键点在这cat.CatShout += Cat.CatShoutEventHandler(mouse1.Run)通过CatShoutEventHandler将Mouse和Cat进行了交互绑定,当cat.CatShout被调用后,执行CatShout事件,通知老鼠猫来了,通知后该事件被委托给mouse1.Run进行处理(赶紧跑)。
添加参数
增加一个类CatShoutEventArgs,让它继承EventArgs,EventArgs是包含事件数据的类的基类。这个的目的就是在CatShout事件触发时,需要传递Cat对象的名字。
public class CatShoutEventArge:EventArgs
{
private string name;
public string Name
{
get {return name;}
set { name = value; }
}
}
改写Cat类的代码,对委托CatShoutEventHandler进行重新定义。增加两个参数,第一个参数Object对象sender是指向发送通知的对象,而第二个参数CatShoutEventArgs的args,包含了所有通知者需要的附件信息,这里是老猫的名字信息。
class Cat
{
private string name;
public Cat(string name)
{
this.name = name;
}
public delegate void CatShoutEventHandler(object sender,CatShoutEventArge args);
//声明委托CatShoutEventHandle
public event CatShoutEventHandler CatShout;
//声明事件CatShout,它的事件类型是委托CatShoutEventHandler
public void Shout()
{
Console.WriteLine ("瞄,我是{0}。",name);
if (CatShout !=null )
{
CatShoutEventArge e = new CatShoutEventArge();
e.Name = this.name;
CatShout(this, e);
}
}
}
在Mouse中改写了一点,由于有了传递过来猫的名字,所以显示的时候就可以指出老猫的名字。
class Mouse
{
private string name;
public Mouse (string name)
{
this.name =name;
}
public void Run(object sender,CatShoutEventArge args)
{
Console.WriteLine ("老猫{0}来了,{1}快跑!",args.Name ,name );
}
Cat类中的Shout方法在触发事件CatShout之前需要判断该事件是否为null。当Cat对象的Shout方法触发事件CatShout后,必须有一个目标函数来处理这个事件,而该语句正是判断该目标函数是否存在。如果将这个判断去掉,且对事件不进行任何绑定而直接调用Shout方法,程序将在事件CatShout处弹出一个NullReferenceException的异常。