当尝试在EventHandler中设置()时,如何检查ManualResetEvent是否已被释放



我有以下设计模式:

    var myObjectWithEvents = new ObjectWithEvents();
    using (var mre = new ManualResetEvent(false)) {
        var onEvent = new EventHandler<EventArgs>((sender, e) => { mre.Set(); });   
        try {
            myObjectWithEvents.OnEvent += onEvent;
            var task = Task.Factory.StartNew(() => {
                myObjectWithEvents.DoSomethingThatShouldRaiseAnEvent();
            });
            var timedOut = !mre.WaitOne(10000);
        }
        finally {
            myObjectWithEvents.OnEvent -= onEvent;
        }
    }

我的问题是,如果在WaitOne超时并且执行步骤超出正在使用的块之后引发OnEvent,则本地onEvent事件处理程序仍将被调用,并尝试设置已经被释放的ManualResetEvent mre,即使onEvent应该已经从OnEvent中注销。

一个简单的解决方法是检查mre是否已经被处理,但不幸的是,没有这样的字段,而且我认为将mre.Set()封装在try-catch块中以忽略异常是不干净的,因为异常可能非常频繁地发生。

您认为在不遇到此类问题的情况下,实现上述代码模式的目的(即等待引发事件)的最佳和最简单的方法是什么?

编辑:感谢您的回答,我创建了以下扩展,并将mre.Set()替换为mre.TrySet():

    public static void TrySet(this ManualResetEvent mre) {
        if (!mre.SafeWaitHandle.IsClosed) mre.Set();
    }
ManualResetEvent.SafeWaitHandle.IsClosed

看起来很奇怪,但dispose所做的唯一一件事就是关闭safeHandler,这是它的dispose打算…的唯一对象

SafeWaitHandle的Dispose将此属性从False更改为True。

您可以尝试通过mre进行检查。SafeWaitHandle.Is关闭属性

作为一个案例,尝试使用简单的布尔开关来指示手动重置事件是否为实际设置:

bool isMreSync = true;
var myObjectWithEvents = new ObjectWithEvents();
using (var mre = new ManualResetEvent(false)) 
{
    var onEvent = new EventHandler<EventArgs>((sender, e) => 
                 { 
                     if (isMreSync)
                     {
                         mre.Set(); 
                     }
                 });
  // try ... finally block  
 }
isMreSync = false;

若事件可能异步执行,则同步对布尔开关的访问。

最新更新