0.前言
事件是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。 任何其他组件都可以订阅事件,并在事件引发时得到通知,在设计模式中叫做观察者模式。和委托类似,事件是后期绑定机制。 用于定义事件以及订阅或取消订阅事件的语法是对委托语法的扩展。
1.事件的使用
在C# GUI程序中,事件处理是很常用的,比如C# WPF中一个按钮的点击,可以对应到一个事件处理方法:
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine(sender.ToString() + ":" + e.ToString());
}
在类的内部声明事件,需要先有一个委托类型。然后,使用event定义一个成员(使用event关键字后,这个委托类型的字段就不能使用=赋值,只能+=或者-=)。其实操作流程和委托差不多,下面的代码定义了一个Sender和一个Receiver类,Sender的事件被传递给Receiver,然后执行事件处理方法。
using System;
namespace TestCS_20191117_event
{
class Program
{
static void Main(string[] args)
{
Sender sender = new Sender();
Receiver receiver = new Receiver();
sender.AHandler += receiver.OnAChanged;
sender.BHandler += receiver.OnBChanged;
sender.CHandler += receiver.OnCChanged;
sender.SomeChange();
Console.ReadKey();
}
}
class Sender
{
//1. 使用自定义的delegate
public delegate void MyEventHandler(string arg);
public event MyEventHandler AHandler;
//2. 使用EventHandler
public class MyArgs:System.EventArgs
{
public MyArgs(string arg)
{
Arg = arg;
}
public string Arg { get; set; }
}
//注意,赋值了一个空委托,这样就不必检查是否有接收者(调用前判断null)
public event EventHandler<MyArgs> BHandler = delegate { };
//3. 声明泛型委托类型
//(where指定约束类型)
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)
where TEventArgs : EventArgs;
//使用上面定义的MyArgs:System.EventArgs来实例化
public event EventHandler<MyArgs> CHandler = delegate { };
//想要引发事件时,使用委托调用语法调用事件处理程序
public void SomeChange()
{
AHandler?.Invoke("AHandler");
BHandler?.Invoke(this, new MyArgs("BHandler"));
CHandler?.Invoke(this, new MyArgs("CHandler"));
}
}
class Receiver
{
public void OnAChanged(string arg)
{
System.Console.WriteLine("a changed:" + arg);
}
public void OnBChanged(object sender,Sender.MyArgs arg)
{
System.Console.WriteLine("b changed:" + arg.Arg);
}
public void OnCChanged(object sender, Sender.MyArgs arg)
{
System.Console.WriteLine("c changed:" + arg.Arg);
}
}
}
2.使用委托完成观察者模式
如果没有事件,我们可以通过多播委托来实现发布-订阅的一个功能。发布者声明一个委托成员,当数据改变时就调用委托,而委托列表中添加了多个订阅者的回调方法。代码如下:
using System;
namespace TestCS_20191117_event
{
class Program
{
static void Main(string[] args)
{
Sender sender = new Sender();
Receiver receiver = new Receiver();
sender.TestChang += receiver.OnTestChanged;
sender.Test = "new test";
Console.ReadKey();
}
}
class Sender
{
public Action<string> TestChang { get; set; }
private string test;
public string Test
{
get { return test; }
set
{
if (value != test)
{
test = value;
// test值改变就调用委托
TestChang?.Invoke(value);
}
}
}
}
class Receiver
{
public void OnTestChanged(string arg)
{
System.Console.WriteLine("test changed:" + arg);
}
}
}
3.参考
MSDN文档:https://docs.microsoft.com/zh-cn/dotnet/csharp/events-overview
书籍:C#本质论