事件模型的五个组成部分
- 事件的拥有者(event source,对象)
- 事件成员(event,成员)
- 事件的响应者(event subscriber,对象)
- 事件处理器(event hander,成员)——本质上是一个回调方法
- 事件订阅——把事件处理器与事件关联在一起,本质上是一种以委托类型为基础的“约定”
模式一
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace EventExample
{
class Program
{
static void Main(string[] args)
{
Timer timer = new Timer();
timer.Interval = 1000;
Boy boy = new Boy();
Girl girl = new Girl();
timer.Elapsed += boy.Action1;
timer.Elapsed += girl.Action2;
timer.Start();
Console.ReadLine();
;
}
}
class Boy
{
internal void Action1(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Jump");
}
}
class Girl
{
internal void Action2(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Singing");
}
}
}
模式二
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Event2
{
class Program
{
static void Main(string[] args)
{
Form form = new Form();
Controller controller = new Controller(form);
form.ShowDialog();
}
}
class Controller
{
private Form form;
public Controller(Form form)
{
this.form = form;
this.form.Click += this.FormClicked;
}
private void FormClicked(object sender, EventArgs e)
{
this.form.Text = DateTime.Now.ToString();
}
}
}
模式三
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Event3
{
class Program
{
static void Main(string[] args)
{
MyForm myForm = new MyForm();
myForm.Click += myForm.Clicked;
myForm.ShowDialog();
}
}
class MyForm : Form
{
internal void Clicked(object sender, EventArgs e)
{
this.Text = DateTime.Now.ToString();
}
}
}
模式四
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Event4
{
class Program
{
static void Main(string[] args)
{
MyForm myForm = new MyForm();
myForm.ShowDialog();
}
}
class MyForm : Form
{
private TextBox textBox;
private Button button;
public MyForm()
{
this.textBox = new TextBox();
this.button = new Button();
this.Controls.Add(this.textBox);
this.Controls.Add(this.button);
this.button.Click += this.ButtonClicked;
this.button.Text = "Say Hello";
this.button.Top = 100;
}
private void ButtonClicked(object sender, EventArgs e)
{
this.textBox.Text = DateTime.Now.ToString();
}
}
}
事件与委托的关系
事件真的是“以特殊方式声明的委托字段/实例”吗?
- 不是!只是声明的时候“看起来像”(对比委托字段与时间的简化声明,field-like)
- 事件声明的时候使用了委托类型,简化声明造成事件看上去像一个委托的字段(实例),而event关键字则更像是一个修饰符——错觉来源之一
- 订阅事件的时候+=操作符后面可以是一个委托实例,这与委托实例的赋值方法语法相同,这也让事件看起来像是一个委托字段——错觉来源之二
- 重申:事件的本质是加装在委托字段上的一个蒙版(mask),是一个起掩蔽作用的包装器。这个用于阻挡非法操作的蒙版绝不是委托字段本身。
为什么要使用委托类型来声明事件?
- 站在source的角度来看,是为了表明source能对外传递哪些消息
- 站在subscriber的角度来看,它是一种约定,是为了约束能够使用什么样签名的方法来处理(响应)事件
- 委托类型的实例将用于存储(引用)事件处理器
对比事件和属性
- 属性不是字段——很多时候属性是字段的包装器,这个包装器用来保护字段不被滥用
- 事件不是委托字段——它是委托字段的包装器,这个包装器用来保护委托字段不被滥用
- 包装器永远都不可能是被包装的东西。