更多关于事件和线程安全

时间:2011-04-17 18:33:29

标签: c# events locking

我在StackOverflow上发现了关于事件和种族的这篇文章,这对我帮助很大 -

C# Events and Thread Safety

这里的关键声明是'即使在事件被取消订阅后,事件处理程序也必须是强大的,否则被调用'

我认为这意味着当您订阅某个活动时,即使您取消订阅该活动,您也必须为该活动做好准备,并进行某种检查以确定是否应该处理该活动。 / p>

这可能与

一样简单(丑陋)
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);

现在很明显,上面的代码看起来很糟糕,但它符合所需的目的。

我的问题是,这样做会更优雅吗?处理这种情况的典型方法是什么?

我想也许你可以做到

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

但是我试过了,我想事件的设计是为了防止你看到其他订阅者。

您怎么看?

由于

2 个答案:

答案 0 :(得分:1)

imho这是一个不存在的问题。您是否有过生成错误(或会产生错误)的代码,因为事件在取消订阅后被调用了?

答案 1 :(得分:0)

事实上,事件会封装多播委托的调用列表,因此您无法直接删除订阅。

取消注册后可以调用处理程序的主要原因(即使您可以从列表中删除订阅)是事件所有者可以制作调用列表的副本。

看看这段代码:

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

第一行创建一个调用列表的副本,以防止在空列表的第4行引发事件(从而保护您免受空引用异常的影响)

因此,如果您在第1行和第4行之间取消注册,则仍会调用您的处理程序,因为已在ev中复制了对它的引用。