事件介绍Introduction to events

上一页Previous

和委托类似,事件是后期绑定机制。Events are, like delegates, a late binding mechanism. 实际上,事件是建立在对委托的语言支持之上的。In fact, events are built on the language support for delegates.

事件是对象用于(向系统中的所有相关组件)广播已发生事情的一种方式。Events are a way for an object to broadcast (to all interested components in the system) that something has happened. 任何其他组件都可以订阅事件,并在事件引发时得到通知。Any other component can subscribe to the event, and be notified when an event is raised.

你可能已在某些编程中使用过事件。You've probably used events in some of your programming. 许多图形系统都具有用于报告用户交互的事件模型。Many graphical systems have an event model to report user interaction. 这些事件会报告鼠标移动、按钮点击和类似的交互。These events would report mouse movement, button presses and similar interactions. 这是使用事件的最常见情景之一,但并非唯一的情景。That's one of the most common, but certainly not the only scenario where events are used.

可以定义应针对类引发的事件。You can define events that should be raised for your classes. 使用事件时,需要注意的一点是特定事件可能没有任何注册的对象。One important consideration when working with events is that there may not be any object registered for a particular event. 必须编写代码,以确保在未配置侦听器时不会引发事件。You must write your code so that it does not raise events when no listeners are configured.

通过订阅事件,还可在两个对象(事件源和事件接收器)之间创建耦合。Subscribing to an event also creates a coupling between two objects (the event source, and the event sink). 需要确保当不再对事件感兴趣时,事件接收器将从事件源取消订阅。You need to ensure that the event sink unsubscribes from the event source when no longer interested in events.

事件支持的设计目标Design goals for event support

事件的语言设计针对这些目标:The language design for events targets these goals:

  • 在事件源和事件接收器之间启用非常小的耦合。Enable very minimal coupling between an event source and an event sink. 这两个组件可能不会由同一个组织编写,甚至可能会通过完全不同的计划进行更新。These two components may not be written by the same organization, and may even be updated on totally different schedules.

  • 订阅事件并从同一事件取消订阅应该非常简单。It should be very simple to subscribe to an event, and to unsubscribe from that same event.

  • 事件源应支持多个事件订阅服务器。Event sources should support multiple event subscribers. 它还应支持不附加任何事件订阅服务器。It should also support having no event subscribers attached.

你会发现事件的目标与委托的目标非常相似。You can see that the goals for events are very similar to the goals for delegates. 因此,事件语言支持基于委托语言支持构建。That's why the event language support is built on the delegate language support.

事件的语言支持Language support for events

用于定义事件以及订阅或取消订阅事件的语法是对委托语法的扩展。The syntax for defining events, and subscribing or unsubscribing from events is an extension of the syntax for delegates.

定义使用 event 关键字的事件:To define an event you use the event keyword:

public event EventHandler<FileListArgs> Progress;

该事件(在此示例中,为 EventHandler<FileListArgs>)的类型必须为委托类型。The type of the event (EventHandler<FileListArgs> in this example) must be a delegate type. 声明事件时,应遵循许多约定。There are a number of conventions that you should follow when declaring an event. 通常情况下,事件委托类型具有无效的返回。Typically, the event delegate type has a void return. 事件声明应为谓词或谓词短语。Event declarations should be a verb, or a verb phrase. 当事件报告已发生的事情时,请使用过去时。Use past tense when the event reports something that has happened. 使用现在时谓词(例如 Closing)报告将要发生的事情。Use a present tense verb (for example, Closing) to report something that is about to happen. 通常,使用现在时表示类支持某种类型的自定义行为。Often, using present tense indicates that your class supports some kind of customization behavior. 最常见的方案之一是支持取消。One of the most common scenarios is to support cancellation. 例如,Closing 事件可能包括指示是否应继续执行关闭操作的参数。For example, a Closing event may include an argument that would indicate if the close operation should continue, or not. 其他方案可能会允许调用方通过更新事件参数的属性来修改行为。Other scenarios may enable callers to modify behavior by updating properties of the event arguments. 你可以引发一个事件以指示算法将采取的建议的下一步操作。You may raise an event to indicate a proposed next action an algorithm will take. 事件处理程序可以通过修改事件参数的属性授权不同的操作。The event handler may mandate a different action by modifying properties of the event argument.

想要引发事件时,使用委托调用语法调用事件处理程序:When you want to raise the event, you call the event handlers using the delegate invocation syntax:

Progress?.Invoke(this, new FileListArgs(file));

委托部分中所介绍的那样,?.As discussed in the section on delegates, the ?. 运算符可以轻松确保在事件没有订阅服务器时不引发事件。operator makes it easy to ensure that you do not attempt to raise the event when there are no subscribers to that event.

通过使用 += 运算符订阅事件:You subscribe to an event by using the += operator:

EventHandler<FileListArgs> onProgress = (sender, eventArgs) =>
    Console.WriteLine(eventArgs.FoundFile);

fileLister.Progress += onProgress;

处理程序方法通常为前缀“On”,后跟事件名称,如上所示。The handler method typically has the prefix 'On' followed by the event name, as shown above.

使用 -= 运算符取消订阅:You unsubscribe using the -= operator:

fileLister.Progress -= onProgress;

请务必为表示事件处理程序的表达式声明局部变量。It's important that you declare a local variable for the expression that represents the event handler. 这将确保取消订阅删除该处理程序。That ensures the unsubscribe removes the handler. 如果使用的是 lambda 表达式的主体,则将尝试删除从未附加过的处理程序,此操作为无效操作。If, instead, you used the body of the lambda expression, you are attempting to remove a handler that has never been attached, which does nothing.

下一篇文章将介绍有关典型事件模式及此示例的不同变体的详细信息。In the next article, you'll learn more about typical event patterns, and different variations on this example.

下一部分Next