I'm sure I've seen this around before but I'm wondering how I should raise an event thread-safely.
I have a message despatch thread which looks somthing like.
while(_messages > 0){
Message msg;
// get next message
if (MessageDispatched != null)
MessageDispatched(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params));
}
I can see that it may be posible for MessageDispatched
to be come null after the check. from a MS blog I've seen:
var handler = MessageDispatched;
if (handler != null)
handler(this, new MessageDispatchedEventArgs(msg.Msg, msg.Params));
Which does stop the possibility of the reference becoming null after the check occurring. I'm wondering how to handle the case where the delegate is disposed (or even if it can?)
Should I just need to stick a try / catch around it, as its probably very rarely going to occur?
Edit
After reading answers I've considered making my class to handle this - quickly it looks something whats below, but I'm running into a few issues which make it not as clean as I want - maybe someone has an idea how to do that?
public class ThreadSafeEvent<TDelegate>
// where TDelegate : Delegate why is this a non allowed special case???
{
List<TDelegate> _delegates = new List<TDelegate>();
public void Subscribe(TDelegate @delegate)
{
lock (_delegates)
{
if (!_delegates.Contains(@delegate))
_delegates.Add(@delegate);
}
}
public void Unsubscibe(TDelegate @delegate)
{
lock (_delegates)
{
_delegates.Remove(@delegate);
}
}
// How to get signature from delegate?
public void Raise(params object[] _params)
{
lock (_delegates)
{
foreach (TDelegate wrappedDel in _delegates)
{
var del = wrappedDel as Delegate;
del.Method.Invoke (del.Target, _params);
}
}
}
}