我有以下设计模式:

    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;
        }
    }

我的问题是,如果OnEvent超时后引发了WaitOne,并且执行了using块之外的步骤,则仍然会调用本地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();
    }

最佳答案

您可以尝试通过mre.SafeWaitHandle.IsClosed属性进行检查

09-30 12:35