如何发布符合 .NET 准则的事件(C# 编程指南)
下面的过程演示了如何将遵循标准 .NET 模式的事件添加到类和结构中。 .NET 类库中的所有事件均基于 EventHandler 委托,定义如下:
public delegate void EventHandler(object sender, EventArgs e);
注意
.NET Framework 2.0 引入了泛型版本的委托 EventHandler<TEventArgs>。 下例演示了如何使用这两个版本。
尽管定义的类中的事件可基于任何有效委托类型,甚至是返回值的委托,但一般还是建议使用 EventHandler 使事件基于 .NET 模式,如下例中所示。
名称 EventHandler
可能导致一些混淆,因为它不会实际处理事件。 EventHandler 和泛型 EventHandler<TEventArgs> 均为委托类型。 其签名与委托定义匹配的方法或 Lambda 表达式是事件处理程序,并将在引发事件时调用。
发布基于 EventHandler 模式的事件
(如果无需随事件一起发送自定义数据,请跳过此步骤转到步骤 3a。)将自定义数据的类声明为对发布服务器和订阅者类均可见的范围。 然后添加所需成员以保留自定义事件数据。 在此示例中,将返回一个简单的字符串。
public class CustomEventArgs : EventArgs { public CustomEventArgs(string message) { Message = message; } public string Message { get; set; } }
(如果使用的是泛型版本 EventHandler<TEventArgs>,请跳过此步骤。)声明发布类中的委托。 为其指定以
EventHandler
结尾的名称。 第二个参数指定自定义EventArgs
类型。public delegate void CustomEventHandler(object sender, CustomEventArgs args);
使用下列步骤之一来声明发布类中的事件。
如果没有任何自定义 EventArgs 类,事件类型将为非泛型 EventHandler 委托。 你无需声明该委托,因为它已在创建 C# 项目时包括的 System 命名空间中声明。 将以下代码添加到发布服务器类。
public event EventHandler RaiseCustomEvent;
如果使用非泛型版本 EventHandler 并且具有派生自 EventArgs 的自定义类,请声明发布类中的事件,并将步骤 2 中的委托用作类型。
public event CustomEventHandler RaiseCustomEvent;
如果使用泛型版本,则无需自定义委托。 而是在发布类中,将事件类型指定为
EventHandler<CustomEventArgs>
,替换尖括号中自定义类的名称。public event EventHandler<CustomEventArgs> RaiseCustomEvent;
示例
下例通过使用自定义 EventArgs 类和 EventHandler<TEventArgs> 作为事件类型来演示之前的步骤。
using System;
namespace DotNetEvents
{
// Define a class to hold custom event info
public class CustomEventArgs : EventArgs
{
public CustomEventArgs(string message)
{
Message = message;
}
public string Message { get; set; }
}
// Class that publishes an event
class Publisher
{
// Declare the event using EventHandler<T>
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
public void DoSomething()
{
// Write some code that does something useful here
// then raise the event. You can also raise an event
// before you execute a block of code.
OnRaiseCustomEvent(new CustomEventArgs("Event triggered"));
}
// Wrap event invocations inside a protected virtual method
// to allow derived classes to override the event invocation behavior
protected virtual void OnRaiseCustomEvent(CustomEventArgs e)
{
// Make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler<CustomEventArgs> raiseEvent = RaiseCustomEvent;
// Event will be null if there are no subscribers
if (raiseEvent != null)
{
// Format the string to send inside the CustomEventArgs parameter
e.Message += $" at {DateTime.Now}";
// Call to raise the event.
raiseEvent(this, e);
}
}
}
//Class that subscribes to an event
class Subscriber
{
private readonly string _id;
public Subscriber(string id, Publisher pub)
{
_id = id;
// Subscribe to the event
pub.RaiseCustomEvent += HandleCustomEvent;
}
// Define what actions to take when the event is raised.
void HandleCustomEvent(object sender, CustomEventArgs e)
{
Console.WriteLine($"{_id} received this message: {e.Message}");
}
}
class Program
{
static void Main()
{
var pub = new Publisher();
var sub1 = new Subscriber("sub1", pub);
var sub2 = new Subscriber("sub2", pub);
// Call the method that raises the event.
pub.DoSomething();
// Keep the console window open
Console.WriteLine("Press any key to continue...");
Console.ReadLine();
}
}
}