简体   繁体   English

有关事件和线程安全的更多信息

[英]More on events and thread safety

I discovered this post on StackOverflow about events and races which helped me immensely - 我在StackOverflow上发现了有关赛事和比赛的信息,这极大地帮助了我-

C# Events and Thread Safety C#事件和线程安全

The key statement here is that 'Event handlers are required to be robust in the face of being called even after the event has been unsubscribed' 这里的关键声明是“即使在取消订阅事件之后,事件处理程序也必须在被调用时保持鲁棒性”

I take this to mean that when you subscribe to an event, you must be prepared for that event to be raised even after you have unsubscribed to it, and do some sort of check to see whether the event should be processed. 我的意思是说,当您订阅某个事件时,即使您尚未订阅该事件,也必须为引发该事件做好准备,并进行某种检查以查看是否应处理该事件。

This could be something as simple (and ugly) as 这可能很简单(很丑)

bool _acceptEvents;

// event handler
void LoggedIn(object sender, EventArgs a)
{
    if (!_acceptEvents) return;

    Evt("Now logged in");
}

// code to unsubscribe to event
_acceptEvents = false;
_parent.LoggedIn -= new LoggedInEventHandler(LoggedIn);

Now obviously the above code is god awful to look at, but it serves the purpose required. 现在显然以上代码令人讨厌,但是它满足了所需的目的。

My question is, what would be a more elegant way of doing this? 我的问题是,这样做会更优雅吗? What is the typical way of handling this situation? 处理这种情况的典型方法是什么?

I had thought perhaps you could do 我以为也许你可以做

if (!_parent.LoggedIn.Contains(myhandler)) return;

but I tried, and I guess events are designed in a way to prevent you from seeing other subscribers. 但是我试过了,我想事件的设计是为了防止您看到其他订阅者。

What do you think? 你怎么看?

Thanks 谢谢

imho it's a non-existing problem. 恕我直言,这是一个不存在的问题。 Have you ever had any code that have generated a bug (or will generate a bug) because an event was called after it was unsubscribed? 您是否曾经有任何代码因取消订阅事件后被调用而产生了错误(或将产生错误)?

Indeed events encapsulate a multicast delegate's invocation list so you can not directly remove your subscription. 实际上,事件封装了多播委托的调用列表,因此您不能直接删除您的订阅。

The main reason that a handler can be called after unregistering (even if you could remove your subscription from the list) is that the event owner could have made a copy of the invocation list. 取消注册后可以调用处理程序的主要原因(即使您可以从列表中删除订阅)也是因为事件所有者可以复制调用列表。

Look at this code: 看下面的代码:

var ev = TheEvent;
if(ev != null)
{
    ev(this, EventArgs.Empty);
}

The first line creates a copy of the invocation list to prevent from raising the event in the 4th line on an empty list (and thereby protecting you from a null reference exception) 第一行创建调用列表的副本,以防止在空列表的第四行引发事件(从而保护您免受空引用异常的影响)

So if you unregister between lines 1 and 4 your handler will still be invoked because a reference to it has been copied in ev . 因此,如果您在第1行和第4行之间注销,则仍会调用处理程序,因为对它的引用已在ev复制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM