Ответ 1
Вы можете попробовать проверить его с помощью свойства mre.SafeWaitHandle.IsClosed
У меня есть следующий шаблон проектирования:
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();
}
Вы можете попробовать проверить его с помощью свойства mre.SafeWaitHandle.IsClosed
ManualResetEvent.SafeWaitHandle.IsClosed
Кажется странным, но единственное, что делает dispose, это закрыть safeHandler, который является единственным объектом, который его предназначение предназначено для...
Утилизация SafeWaitHandle изменяет это свойство с False на True.
В качестве примера попробуйте использовать простой логический переключатель, который указывает, актуальна ли настройка 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;
Если событие может выполняться асинхронно - синхронизируйте доступ к логическому коммутатору.