在 C# 中实现仅支持单个事件处理程序的事件






3.74/5 (6投票s)
2005年11月30日
2分钟阅读

64391

759
本文演示了如何实现一个事件,该事件在给定时间点仅允许一个客户端订阅。 如果多个客户端订阅同一事件(同一对象),则只有最后订阅的客户端会收到事件通知。
引言
本文演示了如何实现一个仅支持单个监听器的事件,即,在给定时间点,只有一个客户端可以订阅该事件。 默认情况下,对于事件,所有订阅的客户端将按顺序收到通知,但在这种情况下,只有最后订阅的客户端会收到通知。
当有多个线程运行并订阅特定事件通知,但只需要一个线程处理此通知时,这种类型的事件非常有用。 对于普通事件,所有线程都会收到通知,并且所有线程都将开始处理通知。 在这种情况下,事件不会发送到所有线程,只有最后一个订阅线程会收到通知。 因此,通知处理方法可能不是线程安全的(可以避免使用内核对象进行同步)。
背景
在 .NET 中,默认情况下,事件表现出多播行为,即,事件通知将按订阅顺序发送给所有订阅该事件的客户端。 将有一个委托列表订阅该事件,并且通知将按顺序发送给所有委托。 这里的问题是,如果任何一个处理程序抛出异常,则其余的处理程序将不会收到通知,即使此异常由事件引发者处理。 有时候(如上述情况),我们需要一个只包含一个事件处理程序的事件,即,它不会堆积处理程序列表并表现出单播行为。
使用代码
运行 SinglecastEvent.exe,将显示一个包含三个按钮和一个文本框的表单,用于显示消息。 单击“客户端 1”按钮。 现在,客户端 1 注册到一个事件,该事件将在单击“引发事件”按钮时触发。 客户端 1 的消息处理程序将在消息文本框中显示消息。 现在,单击“客户端 2”按钮。 再次单击“引发事件”按钮时,该事件将仅由客户端 2 的消息处理程序处理,而客户端 1 将不会收到通知。
代码包含一个类EventRaiser
,该类在单击“引发事件”按钮时引发事件。 此类引发“OnRaiseEvent
”事件,并且客户端(表单)处理此事件。 OnRaiseEvent
的实现如下
private EventHandler OnRaiseEventHandler;
public event EventHandler OnRaiseEvent
{
// Ensure that only one handler can
// be subscribed to this event.
add
{
OnRaiseEventHandler = value;
}
remove
{
OnRaiseEventHandler -= value;
}
}
//
//The following code represents the simulation of clients from the form.
//
private void btnClient1_Click(object sender, System.EventArgs e) {
txtMessages.Text += "Client 1 subscribed to event," +
" other clients will stop listening to event. " +
Environment.NewLine;
// Simulate that client 1 is subscribing
// to the OnRaiseEvent of EventRaiser class
eventRaiser.OnRaiseEvent +=
new EventHandler(Client1_OnRaiseEventHandler);
}
private void btnClient2_Click(object sender, System.EventArgs e) {
txtMessages.Text += "Client 2 subscribed to event, " +
"other clients will stop listening to event." +
Environment.NewLine;
// Simulate that client 2 is subscribing
// to the OnRaiseEvent of EventRaiser class
eventRaiser.OnRaiseEvent +=
new EventHandler(Client2_OnRaiseEventHandler);
}
private void Client1_OnRaiseEventHandler(object sender, EventArgs e)
{
// This is client 1's handler for the event
txtMessages.Text += "Client 1 : event received." +
Environment.NewLine;
}
private void Client2_OnRaiseEventHandler(object sender, EventArgs e)
{
// This is client 2's handler for the event
txtMessages.Text += "Client 2 : event received." +
Environment.NewLine;
}
private void btnRaiseEvent_Click(object sender, System.EventArgs e) {
eventRaiser.RaiseEvent();
}