如何在EventHandler中尝试Set()时检查是否已经处理了ManualResetEvent?

Erw*_*yer 12 .net c# multithreading dispose design-patterns

我有以下设计模式:

    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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

我的问题是,如果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();
    }
Run Code Online (Sandbox Code Playgroud)

Gui*_*non 11

ManualResetEvent.SafeWaitHandle.IsClosed
Run Code Online (Sandbox Code Playgroud)

看起来很奇怪,但处理器唯一做的就是关闭safeHandler,这是其处置意图的唯一对象......

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


Via*_*ukh 7

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