C#委托和事件(参照张子阳的博文)
C#里面的委托其实就是一个函数指针,但是在.NET下面委托是一个类,因此我们可以在类的外面来声明一个委托(作为全局变量)也可以在类的里面来声明委托。所有的委托都是继承自MulticastDelegate, 而MulticastDelegate有时继承自Delegate类。从MulticastDelegate的对象关系图可以得知其下面有两个属性:Method(其实是一个函数指针)用来指向本委托所指向的方法。而Target属性则用来指示该方法的实例,当方法是静态方法时其为空.
委托的声明:public delegate 返回值 委托名(参数列表),这样表示声明一个能以具有相应的参数列表和返回值的函数作为该委托的成员(指向类似函数的指针)。下面就是实例子的代码。
代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication3
{
public delegate void GreetingDelegate(string name);
class Program
{
static void Main(string[] args)
{
myGreet greet = new myGreet();
greet.GreetPeople("Treey",greet.EnglishGreet);
greet.GreetPeople("小明",greet.ChineseGreet);
}
}
class myGreet
{
public void ChineseGreet(string name)
{
Console.WriteLine("早上好 {0}",name);
}
public void EnglishGreet(string name)
{
Console.WriteLine("Good Morning {0}",name);
}
public void GreetPeople(string name,GreetingDelegate myDelegate)
{
myDelegate(name);//在这里这样就实现对相应的方法的封装.调用相应传进来的方法。
}
}
}
接下来是事件:事件其实没什么不好理解的,声明一个事件不过类似于声明一个进行了封装的委托类型的变量而已。事件其实还是一个委托.
主函数代码:
代码
static void Main(string[] args)
{
Heater myHeater = new Heater();
myHeater.BoilEvent += (new Alarm()).MakeAlarm;
myHeater.BoilEvent += (new Display()).ShowMsg;
myHeater.BoilWater();
}
热水器类,也就是被监视对象
代码
/// <summary>
/// 热水器类,也就是监视对象,用来对水进行加热
/// </summary>
public class Heater
{
public delegate void BoilHandler(int para);//声明委托
public event BoilHandler BoilEvent;
private int temperature;
/// <summary>
/// 对水进行加热的函数,BoilEvent(temperature)就是当水加热到一定程度时触发事件调用相应的方法;
/// </summary>
public void BoilWater()
{
for (int i = 0; i < 100; i++)
{
temperature = i;
if (i >= 95)
{
if (null != BoilEvent)
{
BoilEvent(temperature);
}
break;
}
}
}
}
public class Alarm
{
public void MakeAlarm(int param)
{
Console.WriteLine("Alarm:嘀嘀嘀,水已经 {0} 度了:", param);
}
}
public class Display
{
public void ShowMsg(int param)
{
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", param);
}
}
先搞懂 .Net Framework的编码规范:
- 委托类型的名称都应该以EventHandler结束。
- 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArgs类型(或继承自EventArgs)。
- 事件的命名为 委托去掉 EventHandler之后剩余的部分。
- 继承自EventArgs的类型应该以EventArgs结尾。
按照.NET的格式再次编写上面的程序。如果我们是在.NET平台下面的调用事件和上面会有不同,通常返回值为空而且第一个为Object类型,就是事件源,第二个是EventArgs类型,EventArgs是一个类其继承自Object,封装着事件源传递给事件监视者的信息。
代码
public class Heater
{
private int temperature;//类的私有字段
public string type;
public string area;
public delegate void BoiledEventHandler(object sender,BoiledEventArgs e);//声明委托
public event BoiledEventHandler Boiled;
//定义BoiledEventArge类,携带好信息以传递给Observer
public class BoiledEventArgs : EventArgs
{
public readonly int temperature;
public BoiledEventArgs(int temperature)
{
this.temperature = temperature;
}
}
protected virtual void OnBoiled(BoiledEventArgs e)
{
if (null!=Boiled)
{
Boiled(this,e);
}
}
/// <summary>
/// 烧水
/// </summary>
public void BoilWater()
{
for (int i = 0; i < 100; i++)
{
this.temperature = i;
if (95==i)
{
BoiledEventArgs e =new BoiledEventArgs(temperature);//声明事件的参数
OnBoiled(e);//调用OnBoiled方法触发事件
}
}
}
}
public class Alarm
{
public void MakeAlarm(object sender,Heater.BoiledEventArgs e)
{
Heater myHeater = new Heater();
Console.WriteLine("Display:{0} - {1}: ", myHeater.area,myHeater.type);
Console.WriteLine("Display:水快烧开了,当前温度:{0}度。", e.temperature);
Console.WriteLine();
}
}