Как проверить, был ли установлен ManualResetEvent при попытке установить() внутри EventHandler?

У меня есть следующий шаблон проектирования:

    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, а выполнение выполняется из блока использования, локальный обработчик событий OnEvent все равно будет вызываться и попытаться установить ManualResetEvent mre, который будет уже были удалены, хотя OnEvent должен был быть незарегистрирован из OnEvent.

Простым обходным решением было бы проверить, был ли уже установлен mre, но, к сожалению, такого поля нет, и я считаю, что обертка mre.Set() внутри блока catch try для игнорирования исключения не является чистой, учитывая, что исключение может происходить довольно часто.

Что вы предложите как лучший и самый простой способ достичь цели вышеуказанного шаблона кода (т.е. ожидание создания события), не сталкиваясь с такой проблемой?

Изменить:. Благодаря вашим ответам я создал следующее расширение и заменил mre.Set() на mre.TrySet():

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

Ответ 1

Вы можете попробовать проверить его с помощью свойства mre.SafeWaitHandle.IsClosed

Ответ 2

ManualResetEvent.SafeWaitHandle.IsClosed

Кажется странным, но единственное, что делает dispose, это закрыть safeHandler, который является единственным объектом, который его предназначение предназначено для...

Утилизация SafeWaitHandle изменяет это свойство с False на True.

Ответ 3

В качестве примера попробуйте использовать простой логический переключатель, который указывает, актуальна ли настройка manualResetEvent:

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;

Если событие может выполняться асинхронно - синхронизируйте доступ к логическому коммутатору.