委托和事件是两种类型,而字段和属性是具体的对象,虽然都是封装,但两者之间还是有区别的,事件对委托的封装是在类级别的、抽象层次、稳定的封装,而属性对字段的封装是在对象级别的、具体的、可定义的封装。
MSDN中有这么一句:“事件是特殊类型的多路广播委托,仅可从声明它们的类或结构(发行者类)中调用。”如此看来事件与委托的关系应该是继承关系,在继承的过程中在EventHandler类中进行的封装。
用代码来比较委托和事件,分别用事件和委托来实现实现一个非常简单的功能:控制台输入一个数,如果输入100的话就显示"Game Over"。
事件实现代码:
static void Main(string[] args)
{
//事件实现
Game1 game = new Game1();
game.GameOverEvent += game_GameOver;
while (true)
{
Console.WriteLine("输入:");
game.Scroe = Convert.ToInt32(Console.ReadLine());
}
}
static void game_GameOver(object sender, EventArgs e)
{
Console.WriteLine("Game Over");
}
static void game_GameOver()
{
Console.WriteLine("Game Over");
}
//事件实现
class Game1
{
//event 关键字用于在发行者类中声明事件。
public event EventHandler GameOverEvent;
private int scroe;
public int Scroe
{
get { return scroe; }
set
{
this.scroe = value;
if (this.GameOverEvent != null)
{
if (value == 100)
{
this.GameOverEvent(this, new EventArgs());//触发事件
}
}
}
}
}
委托实现代码:
class Program
{
static void Main(string[] args)
{
//委托实现
Game2 game = new Game2();
game.AddMethod(game_GameOver);
while (true)
{
Console.WriteLine("输入:");
game.Scroe = Convert.ToInt32(Console.ReadLine());
}
}
static void game_GameOver(object sender, EventArgs e)
{
Console.WriteLine("Game Over");
}
static void game_GameOver()
{
Console.WriteLine("Game Over");
}
}
//委托实现
class Game2
{
public delegate void OverDelegate();
//将委托声明为private,防止订阅者直接调用,使用new等功能
private OverDelegate GameOverDelegate;
//AddMethod和RemoveMethod模拟事件的+=和-=赋值
public void AddMethod(OverDelegate over)
{
this.GameOverDelegate += over;
}
public void RemoveMethod(OverDelegate over)
{
this.GameOverDelegate -= over;
}
private int scroe;
public int Scroe
{
get { return scroe; }
set
{
this.scroe = value;
if (this.GameOverDelegate != null)
{
if (value == 100)
{
this.GameOverDelegate();//触发委托
}
}
}
}
}
Game1在此就是发布者类,对事件GameOverEvent的封装还是在发布者类中完成的,并不是在EventHandler类中就已经完成。这种封装模式和属性对字段的封装模式是完全一样的,只不过这个封装过程是由于有了event关键字在编译阶段由编译器自动完成的,在发布者类中将EventHandler类型的GameOverEvent委托设为私有,并加上Add和Remove方法,和上面用委托模拟的事件是一样的,也就是事件的本质就是在小标题2中用委托模拟的事件。这么说来,事件对委托的封装是可以类比为属性对字段的封装的,如果说有区别,那就是前者是编译阶段完成的、不可自定义的封装,后者是coding阶段实现的、可自定义的封装,但它们都是在对象级别完成的。