There are basically two patterns in avoiding duplicated registering of event handlers: (According to this discussion: C# pattern to prevent an event handler hooked twice)
<I don't think this matters a lot, both in assumed performance gain and actual difference.
Both GetInvocationList
and -=
walk the internal array _invocationList
. (See source)
The LINQ extension method Contains
will take more time since it needs the entire array to be walked and converted, returned and then checked by Contains
itself. The Contains
has the advantage it doesn't need to add the event handler if it exists which will mean some performance gain.
According the documentation, invocation list is being stored as array or something similar to it, and the order of the event handlers is being stored too. May be there are inner structure to maintain fast search for a particular method there.
So in the worst case operation of the GetInvocationList().Contains(MyEventHandlerMethod);
is O(1)
(as we simply got the reference for the array) + O(n)
for searching the method, even if there is no optimization for it. I seriously doubt that this is true, and I think that there is some optimizing code, and it is O(log_n)
.
Second approach has additional operation of adding which is, I think, O(1)
, as we adding the event handler to the end.
So, to see the difference between such actions, you need a lot of the event handlers.
But! If you use the second approach, as I said, you'll add the event handler to the end of the queue, which can be wrong in some cases. So use the first one, and has no doubt in it.
The typical usage would be "subscribe {some usage} [unsubscribe]" where the unsubscribe may not be necessary, depending on the relative lifetimes of the event publisher and subscriber; if you actually have a re-entrant scenario, then "subscribe if not already subscribed" is itself problematic, because when unsubscribing later, you don't know if you're preventing an outer iteration receiving the event.
MyEvent -= MyEventHandlerMethod
first need to find the registered event handler in the invocation list in order to remove it.
So GetInvocationList().Contains
is better, but it's truely insignificant.
But, notice that you can't access event EventHandler foo
's invocation list....