事件设计

注释

此内容由 Pearson Education, Inc. 的许可从 框架设计指南:可重用 .NET 库的约定、习惯和模式(第 2 版)重新打印。 该版于2008年出版,此后该书已于 第三版全面修订。 此页上的一些信息可能已过期。

事件是最常见的回调形式(允许框架调用用户代码的构造)。 其他回叫机制包括采用委托的成员、虚拟成员和基于接口的插件。可用性调查中的数据显示,大多数开发人员更喜欢使用事件,而不是使用其他回叫机制。 事件与 Visual Studio 和多种语言很好地集成。

请务必注意的是,有两组事件:在系统状态发生更改之前引发的事件、称为预事件,以及状态更改后引发的事件(称为后事件)。 预事件的一个例子是 Form.Closing,它会在窗体关闭之前触发。 后期事件的一个例子是 Form.Closed,它是在窗体关闭后引发的。

✔️ 请对事件使用“raise”(引发)这个词,而不是使用“fire”(激发)或“trigger”(触发)。

✔️ 请使用 System.EventHandler<TEventArgs>,而不是手动创建新的委托来用作事件处理程序。

✔️ 请考虑使用作为事件参数的 EventArgs 子类,除非绝对确定事件永远不需要将任何数据传送到事件处理方法,在这种情况下,可以直接使用该 EventArgs 类型。

如果你直接使用 EventArgs 来传递 API,则你永远无法在不破坏兼容性的情况下添加任何要与事件一起传递的数据。 如果使用子类,即使最初完全为空,也能够在需要时向子类添加属性。

✔️ 请使用受保护的虚拟方法来引发每个事件。 这仅适用于未密封类上的非静态事件,不适用于结构、密封类或静态事件。

该方法的目的是为派生类提供一种方法,以便使用替代处理事件。 对于处理派生类中的基类事件,替代操作更加灵活、更加快速,也更自然。 按照约定,该方法的名称应以“On”开头,后接事件的名称。

派生类可以选择不在其重写中调用方法的基本实现。 为此,请不要在为使基类正常工作而所需的方法中包含任何处理。

✔️ 请将一个参数传递给会引发事件的受保护的方法。

参数应命名 e ,应键入为事件参数类。

❌ 引发非静态事件时,请勿将 null 作为发送方传递。

✔️ 在引发静态事件时,请将 NULL 作为发送方传递。

❌ 引发事件时,请勿将 null 作为事件数据参数传递。

如果不想将任何数据传递给事件处理方法,则应传递 EventArgs.Empty 。 开发人员期望此参数不为 null。

✔️ 请考虑引发最终用户可取消的事件。 这仅适用于预事件。

使用 System.ComponentModel.CancelEventArgs 或其子类作为事件参数,以允许最终用户取消事件。

自定义事件处理程序设计

在某些情况下,EventHandler<T> 无法使用,例如当框架需要与不支持泛型的较早版本的 CLR 一起工作时。 在这种情况下,你可能需要设计和开发自定义事件处理程序委托。

✔️ 请对事件处理程序使用返回类型 void。

事件处理程序可以对多个对象调用多个事件处理方法。 如果允许事件处理方法返回一个值,则每个事件调用将有多个返回值。

✔️ 请将 object 用作事件处理程序的第一个参数的类型,并将其命名为 sender

✔️ DO 使用 System.EventArgs 或其子类作为事件处理程序的第二个参数的类型,并调用它 e

❌ 在事件处理程序上不要具有两个以上的参数。

部分内容 © 2005, 2009 Microsoft 公司。 保留所有权利。

获得皮尔逊教育公司许可后重印自 框架设计准则:可重用 .NET 库的约定、习惯和模式 ,由 Krzysztof Cwalina 和 Brad Abrams 编写,并作为微软 Windows 开发系列中的出版物之一,于 2008 年 10 月 22 日由 Addison-Wesley Professional 出版。

另请参阅