1.事件委托声明
.NET 类库中的所有事件均基于 EventHandler 委托、EventHandler<TEventArgs> 委托,一般不建议自定义委托。
//未生成事件数据的委托
public delegate void EventHandler(object? sender, EventArgs e);
//生成事件数据的委托
public delegate void EventHandler<TEventArgs>(object? sender, TEventArgs e);
//自定义委托
public delegate void CustomEventHandler(object sender, CustomEventArgs args);
第一个参数为object
类型,表示能够引发事件的类的实例。
第二个参数为从 EventArgs 基类派生的子类型的实例。如果事件不生成事件数据,第二个参数就是 EventArgs.Empty 字段的值。如果事件生成事件数据,则提供保存事件数据所需的任何字段或属性。
2.事件声明
事件的声明方式与字段相似,区别是事件声明包括 event
关键字,且类型必须是委托类型。
event 委托类型 事件名;
//EventHandler委托类型
public event EventHandler RaiseCustomEvent;
//EventHandler<CustomEventArgs>委托类型
public event EventHandler<CustomEventArgs> RaiseCustomEvent;
//自定义委托类型
public event CustomEventHandler RaiseCustomEvent;
3.订阅事件和取消订阅
通过使用 +=
运算符订阅事件,使用 -=
运算符取消订阅。
pub.RaiseCustomEvent += HandleCustomEvent;
pub.RaiseCustomEvent -= HandleCustomEvent;
4.事件访问器
实际上,目标方法是通过事件访问器添加到委托的调用列表中,事件访问器类似于属性访问器,不同之处在于事件访问器命名为 add
和 remove
。 在大多数情况下,无需提供自定义事件访问器。 如果代码中没有提供自定义事件访问器,编译器将自动添加它们。 但在某些情况下,编译器不自动添加它们,可能需要我们自己提供自定义行为,比如:类继承自两个或多个接口,且每个接口都具有相同名称的事件。 在这种情况下,我们必须为至少其中一个事件提供显式接口实现。为事件编写显式接口实现时,还必须编写 add
和 remove
事件访问器。
event EventHandler IDrawingObject.OnDraw
{
add
{
lock (objectLock)
{
PreDrawEvent += value;
}
}
remove
{
lock (objectLock)
{
PreDrawEvent -= value;
}
}
}
5.完整示例
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();
}
}
}
6.修饰符
事件支持 abstract、new、override、sealed、static、virtual
修饰符。
原创文章,作者:huoxiaoqiang,如若转载,请注明出处:https://www.huoxiaoqiang.com/csharp/csharplang/8221.html