I have the following design pattern:
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;
}
}
My issue is that if OnEvent
is raised after the WaitOne
times out and execution steps out of the using block, the local onEvent
event handler will still be called and try to set the ManualResetEvent mre
which will have already been disposed, even though onEvent
should have been unregistered from OnEvent
.
A simple workaround would be to check if mre
has already been disposed, but unfortunately there is no such field, and I believe wrapping mre.Set()
inside a try catch block to ignore the exception is not clean given that the exception could occur quite frequently.
What would you suggest as the best and simplest way to achieve the purpose of the above code pattern (i.e. waiting for an event to be raised) without running into this kind of issue?
Edit: Thanks to your answers, I created the following extension and replaced mre.Set()
with mre.TrySet()
:
public static void TrySet(this ManualResetEvent mre) {
if (!mre.SafeWaitHandle.IsClosed) mre.Set();
}
ManualResetEvent.SafeWaitHandle.IsClosed
Seems strange, but the only thing that the dispose does is to close the safeHandler, which is the only object that its the dispose intended to...
The Dispose of the SafeWaitHandle, changes this property from False to True.
You can try to check it by the mre.SafeWaitHandle.IsClosed property
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With