我确定我之前已经看过这个,但我想知道如何安全地提升一个事件。
我有一个消息发送线程看起来像。
while(_messages > 0){
Message msg;
// get next message
if (MessageDispatched != null)
MessageDispatched(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params));
}
我可以看到MessageDispatched
在检查后变为空可能是可能的。来自我见过的MS博客:
var handler = MessageDispatched;
if (handler != null)
handler(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params));
这确实阻止了在检查发生后引用变为空的可能性。我想知道如何处理委托被处置的情况(或者即使它可以?)
我是否只需要坚持尝试/捕捉它,因为它很可能很少发生?
修改的
在阅读完答案后,我考虑让我的班级来处理这个问题 - 很快就会看到下面的内容,但我遇到了一些问题,这些问题使得它不像我想要的那么干净 - 也许有人知道如何那样做?
public class ThreadSafeEvent<TDelegate>
// where TDelegate : Delegate why is this a non allowed special case???
{
List<TDelegate> _delegates = new List<TDelegate>();
public void Subscribe(TDelegate @delegate)
{
lock (_delegates)
{
if (!_delegates.Contains(@delegate))
_delegates.Add(@delegate);
}
}
public void Unsubscibe(TDelegate @delegate)
{
lock (_delegates)
{
_delegates.Remove(@delegate);
}
}
// How to get signature from delegate?
public void Raise(params object[] _params)
{
lock (_delegates)
{
foreach (TDelegate wrappedDel in _delegates)
{
var del = wrappedDel as Delegate;
del.Method.Invoke (del.Target, _params);
}
}
}
}
答案 0 :(得分:1)
后一种结构将确保您不会在非Itanium体系结构上调用处理程序时出现空引用异常。
但是,它会导致另一个可能的问题 - 注册事件处理程序的客户端可能会在被删除之后将处理程序称为。防止这种情况的唯一方法是序列化引发事件并注册处理程序。但是,如果这样做,则可能存在死锁情况。
简而言之,这有三种可能的方法可以解决 - 我采用你在这里完成它的方式(和MS推荐)并接受事件处理程序可能在它被调用之后被调用未注册的。
答案 1 :(得分:1)
阅读Eric Lippert的这篇文章:Events and Races
答案 2 :(得分:0)