65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.74/5 (6投票s)

2005年11月30日

2分钟阅读

viewsIcon

64391

downloadIcon

759

本文演示了如何实现一个事件,该事件在给定时间点仅允许一个客户端订阅。 如果多个客户端订阅同一事件(同一对象),则只有最后订阅的客户端会收到事件通知。

Sample Image - SinglecastEvent.jpg

引言

本文演示了如何实现一个仅支持单个监听器的事件,即,在给定时间点,只有一个客户端可以订阅该事件。 默认情况下,对于事件,所有订阅的客户端将按顺序收到通知,但在这种情况下,只有最后订阅的客户端会收到通知。

当有多个线程运行并订阅特定事件通知,但只需要一个线程处理此通知时,这种类型的事件非常有用。 对于普通事件,所有线程都会收到通知,并且所有线程都将开始处理通知。 在这种情况下,事件不会发送到所有线程,只有最后一个订阅线程会收到通知。 因此,通知处理方法可能不是线程安全的(可以避免使用内核对象进行同步)。

背景

在 .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();
}
© . All rights reserved.