先直接上图解C#中的代码吧
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
/// <summary>
/// 发布者:发布某个事件的类或结构
/// 订阅者:注册并在事件发生时得到通知的类或结构
/// 事件处理程序:由订阅者注册到事件的方法
/// 触发事件:当事件触发时所有注册到它的方法都会被一次调用
/// </summary>
namespace 事件
{
delegate void Handler();
/// <summary>
/// 发布者
/// </summary>
class Incrementer
{
public event Handler CountedADozen;//创建事件并发布
public void DoCount()
{
for (int i = 1; i < 100; ++i) {
if (i%12 == 0 && CountedADozen!=null ) {
CountedADozen();//触发事件
}
}
}
}
/// <summary>
/// 订阅者
/// </summary>
class Dozens
{
public int DozensCount { get; private set; }
public Dozens ( Incrementer incrementer)
{
DozensCount = 0;
incrementer.CountedADozen += IncrementerDozensCount;//订阅事件
}
void IncrementerDozensCount()//声明事件处理程序
{
DozensCount++;
}
}
class Program
{
static void Main(string[] args)
{
Incrementer incrementer = new Incrementer( );
Dozens dozensCounter = new Dozens( incrementer );
incrementer.DoCount();
Console.WriteLine( "Number of dozens = {0}", dozensCounter.DozensCount );
}
}
}
从上面的代码看事件不是委托的实例。在深入理解C#一书中提到,对于事件来说,必须是一个委托类型,它只是成对的remove/add方法,和属性的取值方法,赋值方法很像。
event关键字对委托做了一个封装,只能通过+=和-=来添加和删除方法,也就是注册和取消事件。
在网上的一篇博客http://www.cnblogs.com/fire-dragon/p/5918790.html看到,作者认为event使得被修饰的委托类型变量访问属性变成了private。在深入理解C#一书中写道:
编译器会将声明转换成一个具有默认add/remove实现的事件和一个私有委托类型的字段。类内的代码能看见字段,类外的代码只能看见事件。
最后一句表明,类外的代码是看不见那个event修饰的私有委托类型的字段。
那么为什么+=和-=可以在类外对被修饰的字段使用呢,可能类似于C++的运算符重载,+=,-=其实相当于一个函数,可能是在函数内对event修饰的私有委托类型字段做出的修改。我觉得可能就像下面这样,a是私有的,无奈有个成员函数破坏了封装。
class A{
private int a;
public void set( int a ){
this.a = a
}
}
在观察者模式中,事件的定义与注册发生在被观察者那,事件是私有的一个好处就是在类外无法访问,这样对于事件的行为就完全由被观察者决定,出错的可能性大大减少。
参考:http://www.cnblogs.com/fire-dragon/p/5918790.html
http://www.cnblogs.com/asdyzh/p/9944304.html
图解C#
深入理解C#