C# 事件(Event)

事件是对象发送的通知,用于表示操作的发生。.NET中的事件遵循观察者设计模式。

引发事件的类称为 Publisher(发布者),接收通知的类称为 Subscriber(订阅者)。一个事件可以有多个订阅者。通常,发布者在发生某个操作时引发事件。订阅者希望在操作发生时获得通知,他们应该向事件注册并处理它。

在C#中,事件是封装的委托。它取决于委托。委托为订阅者类的事件处理程序方法定义签名。

下图说明了C#中的事件。

活动发布者-订阅者
事件发布者和订阅者

通过事件使用委托

事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布者(publisher) 类。其他接受该事件的类被称为 订阅者(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。

发布者(publisher)- 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布者(publisher)类的对象调用这个事件,并通知其他的对象。

订阅者(subscriber)- 是一个接受事件并提供事件处理程序的对象。在发布者(publisher)类中的委托调用订阅者(subscriber)类中的方法(事件处理程序)。

声明事件

可以通过两个步骤声明一个事件:

  1. 声明委托

  2. 使用 event 关键字声明委托的变量

下面的示例演示如何在发布者类中声明事件。

publicdelegatevoidNotify();//委托publicclassProcessBusinessLogic{publiceventNotifyProcessCompleted;//事件}

在上面的示例中,我们声明了一个委托 Notify,然后在 ProcessBusinessLogic 类中使用“event”关键字声明了委托类型Notify的事件ProcessCompleted。因此,ProcessBusinessLogic类称为publisher(发布者)。Notify委托指定ProcessCompleted事件处理程序的签名。它指定subscriber(订阅者)类中的事件处理程序方法必须具有 void 返回类型,并且没有参数。

现在,让我们看看如何引发ProcessCompleted事件。请看以下实现。

publicdelegatevoidNotify();//委托publicclassProcessBusinessLogic{publiceventNotifyProcessCompleted;//事件publicvoidStartProcess(){Console.WriteLine("ProcessStarted!");//一些代码在这里..OnProcessCompleted();}protectedvirtualvoidOnProcessCompleted()//受保护的虚方法{//如果ProcessCompleted不为null,则调用委托ProcessCompleted?.Invoke();}}

上面,StartProcess()方法在末尾调用onProcessCompleted()方法,这将引发一个事件。通常,要引发事件,应使用<EventName>上的名称定义protected和virtual方法。受保护和虚拟使派生类重写引发事件的逻辑。但是,派生类应该始终调用基类的On<EventName>方法,以确保注册的委托接收事件。

OnProcessCompleted() 方法使用 ProcessCompleted?. invoke() 调用委托。这将调用所有注册到 ProcessCompleted 事件的事件处理程序方法。

订阅者类必须注册到ProcessCompleted事件,并使用签名匹配Notify委托的方法来处理它,如下所示。

classProgram{publicstaticvoidMain(){ProcessBusinessLogicbl=newProcessBusinessLogic();bl.ProcessCompleted+=bl_ProcessCompleted;//注册事件bl.StartProcess();}//事件处理程序publicstaticvoidbl_ProcessCompleted(){Console.WriteLine("ProcessCompleted!");}}

上面,Program 类是 ProcessCompleted 事件的订阅者。它使用 + = 运算符向事件注册。请记住,这与我们在多播委托的调用列表中添加方法的方式是一样的。bl_processcompleted ()方法处理该事件,因为它与 Notify 委托的签名匹配。

内置 EventHandler 委托

.NET Framework包含用于最常见事件的内置委托类型EventHandler和EventHandler <TEventArgs>。通常,任何事件都应包括两个参数:事件源和事件数据。。对不包含事件数据的所有事件使用EventHandler委托。对于包含要发送到处理程序的数据的事件,请使用 EventHandler<TEventArgs> 委托。

上面显示的示例可以使用EventHandler委托,而无需声明自定义Notify委托,如下所示。

在上面的示例中,事件处理程序bl_ProcessCompleted()方法包含两个与 EventHandler 委托匹配的参数。同时,传递 this 作为发送者和EventArgs。当我们在OnProcessCompleted()方法中使用Invoke()引发事件时为空。因为我们的事件不需要任何数据,它只是通知订阅者流程已经完成,所以我们传递了 EventArgs.Empty。

传递事件数据

大多数事件向订阅者发送一些数据。EventArgs类是所有事件数据类的基类。NET包含许多内置事件数据类,如 SerialDataReceivedEventArgs。它遵循以EventArgs结束所有事件数据类的命名模式。您可以通过派生 EventArgs 类为事件数据创建自定义类。

使用EventHandler <TEventArgs>将数据传递到处理程序,如下所示。

classProgram{publicstaticvoidMain(){ProcessBusinessLogicbl=newProcessBusinessLogic();bl.ProcessCompleted+=bl_ProcessCompleted;//事件注册bl.StartProcess();}//事件处理publicstaticvoidbl_ProcessCompleted(objectsender,boolIsSuccessful){Console.WriteLine("Process"+(IsSuccessful?"CompletedSuccessfully":"failed"));}}publicclassProcessBusinessLogic{//使用内置EventHandler声明事件publiceventEventHandler<bool>ProcessCompleted;publicvoidStartProcess(){try{Console.WriteLine("ProcessStarted!");//一些代码在这里..OnProcessCompleted(true);}catch(Exceptionex){OnProcessCompleted(false);}}protectedvirtualvoidOnProcessCompleted(boolIsSuccessful){ProcessCompleted?.Invoke(this,IsSuccessful);}}

在上面的示例中,我们将单个布尔值传递给处理程序,以指示该过程是否成功完成。

如果希望将多个值作为事件数据传递,那么可以创建一个从 EventArgs 基类派生的类,如下所示。

classProcessEventArgs:EventArgs{publicboolIsSuccessful{get;set;}publicDateTimeCompletionTime{get;set;}}

下面的示例演示如何将自定义 ProcessEventArgs 类传递给处理程序。

classProgram{publicstaticvoidMain(){ProcessBusinessLogicbl=newProcessBusinessLogic();bl.ProcessCompleted+=bl_ProcessCompleted;//事件注册bl.StartProcess();}//事件处理publicstaticvoidbl_ProcessCompleted(objectsender,ProcessEventArgse){Console.WriteLine("Process"+(e.IsSuccessful?"CompletedSuccessfully":"failed"));Console.WriteLine("CompletionTime:"+e.CompletionTime.ToLongDateString());}}publicclassProcessBusinessLogic{//使用内置EventHandler声明事件publiceventEventHandler<ProcessEventArgs>ProcessCompleted;publicvoidStartProcess(){vardata=newProcessEventArgs();try{Console.WriteLine("ProcessStarted!");//一些代码在这里..data.IsSuccessful=true;data.CompletionTime=DateTime.Now;OnProcessCompleted(data);}catch(Exceptionex){data.IsSuccessful=false;data.CompletionTime=DateTime.Now;OnProcessCompleted(data);}}protectedvirtualvoidOnProcessCompleted(ProcessEventArgse){ProcessCompleted?.Invoke(this,e);}}

因此,您可以在C#中创建,引发,注册和处理事件。

要记住的要点

  1. 事件是对委托的包装。这取决于委托。

  2. 将“ event”关键字与委托类型变量一起使用来声明事件。

  3. 将内置委托EventHandler或EventHandler <TEventArgs>用于常见事件。

  4. 发布者类引发一个事件,而订阅者类注册一个事件并提供事件处理程序方法。

  5. 用事件名称命名引发事件的方法,该方法以“ On”为前缀。

  6. 处理程序方法的签名必须与委托签名匹配。

  7. 使用+ =运算符注册事件。使用 -= 运算符取消订阅,不能使用=运算符。

  8. 使用EventHandler <TEventArgs>传递事件数据。

  9. 派生EventArgs基类以创建自定义事件数据类。

  10. 可以将事件声明为静态,虚拟,密封和抽象(static, virtual, sealed, abstract)。

  11. 接口可以将事件作为成员包含。

  12. 如果有多个订阅者,则将同步调用事件处理程序。

编辑于2024-05-20 13:05