How to call all event handlers concurrently bind to an event - c#

Couple of days ago I faced a question that How to call all the Event handler bind to an event in parallel.
My questions are:
how to get the list of all the event handler bound to an event?
while I would be calling all the event handlers, no one should be able to add a new event handler to that event. So, basically I need to acquire lock while I am calling event handler. So, how to address this issue in c#?

To get the list of all listeners bound to an event, use GetInvocationList
Since delegates are immutable, all you have to do is grab a reference to the delegate itself. If someone adds a listener to the shared event, a new one will be created - and the one you're iterating over will remain unchanged. No locks required.
EventHandler handler = OnEvent;
if (handler != null)
{
Parallel.ForEach(handler.GetInvocationList(),
del => del.DynamicInvoke(this, EventArgs.Empty));
}

Do you mean getting the invocation list?
var handler = MyHandler;
if (handler != null)
{
var invocationList = handler.GetInvocationList();
foreach (EventHandler receiver in invocationList)
receiver.BeginInvoke(this, EventArgs.Empty, null, null);
}
you can simply lock the invocation by using a lock(_myLock) statement around that codeblock.

Related

Switching between event handlers of dispatcherTimer tick event

in my application I have dispatcherTimer and few eventHandlers which I use on dispatcherTimer.Tick event:
dt.Tick += myEventHandler1
when I want to switch event handlers of the tick I use sth like this:
dt.Tick -= myEventHandler1
dt.Tick += myEventHandler2
Is it correct way ?
Should I check if dt.Tick is not null before that ?
Also what is the best way to remove all eventHandlers from dt.Tick event ?
I use .net 3.5
thank You very much for help
You need not check for nullity before adding or removing an event handler however you do need to check for nullity before raising the event.
In order to remove all of the event handlers you will have to remove the event handlers manually as you have already or write a function to do so automatically using reflection.
private void RemoveHandlers(DispatcherTimer dispatchTimer)
{
var eventField = dispatchTimer.GetType().GetField("Tick",
BindingFlags.NonPublic | BindingFlags.Instance);
var eventDelegate = (Delegate) eventField.GetValue(dispatchTimer);
var invocatationList = eventDelegate.GetInvocationList();
foreach (var handler in invocatationList)
dispatchTimer.Tick -= ((EventHandler) handler);
}
In the context of a delegate you could simply assign null in order to remove all of the handlers from the chain however events inherently prevent this.

Invoke of an EventHandler

I have the following EventHandler:
private EventHandler<MyEventArgs> _myEventHandler;
public event EventHandler<MyEventArgs> MyEvent
{
add { _myEventHandler += value; }
remove { _myEventHandler -= value; }
}
Could somebody explain the difference between the following snippets?
Snippet EventHandler (A):
//Snippet A:
if (_myEventHandler != null)
{
_myEventHandler(new MyEventArgs());
}
Snippet BeginInvoke (B):
//Snippet B:
if (_myEventHandler != null)
{
_myEventHandler.BeginInvoke(new MyEventArgs(), ar =>
{
var del = (EventHandler<MyEventArgs>)ar.AsyncState;
del.EndInvoke(ar);
}, _myEventHandler);
}
For clarification: What's the difference between invoking an EventHandler "just as it is" and using BeginInvoke?
The BeginInvoke approach is async, meaning that it is raised on a different thread. This can be dangerous if people don't expect it, and is pretty rare for events - but it can be useful.
Also, note that strictly speaking you should snapshot the event handler value - this is especially true if (via Begin*) you are dealing with threads.
var tmp = _myEventHandler;
if(tmp != null) {
tmp(sender, args);
}
Also - note that your event subscription itself is not thread-safe; again, this only matters if you are dealing with multi-threading, but the inbuilt field-like event is thread-safe:
public event EventHandler<MyEventArgs> MyEvent; // <===== done; nothing more
The issues avoided here are:
with the snapshot, we avoid the risk of the last subscriber unsubscribing between the null-check and the invoke (it does mean they might get an event they didn't expect, but it means we don't kill the raising thread)
with the field-like event change we avoid the risk of losing subscriptions / unsubscriptions when two threads are doing this at the same time
BeginInvoke() call immediatelly returns control to the calling thread and run a delegate in a separate thread from the ThreadPool, so this will be some kind of asynchronous execution.

Does an event need to have at least one handler?

Why event needs to have at least one handler?
I created custom event for my Control and somewhere inside of code of my control, I call this event:
this.MyCustomEvent(this, someArgs);
it throws a NullReferenceException if there is no handler subscribed to it.
When I added a single handler in control's constructor, everything works fine:
this.MyCustomEvent += myCutomEventHandler;
void myCustomEventHandler(object sender, EventArgs e)
{ /* do nothing */ }
Is this normal or maybe I'm doing something wrong?
Shouldn't it check automatically if there are any handlers subscribed? It's a little dumb, IMHO.
I recommend you to have an extremely useful extension method:
public static void Raise<T>(this EventHandler<T> eventHandler, object sender, T e) where T : EventArgs
{
if (eventHandler != null)
{
eventHandler(sender, e);
}
}
which will do the check for you.
Usage:
MyCustomEvent.Raise(this, EventArgs.Empty);
Note that delegates are reference types, and their default value is null.
The solution proposed by others, i.e. to check for null before firing the event, is not thread-safe because listeners may unsubscribe from the event between the null check and the firing of the event.
I have seen solutions that involve copying the delegate to a local variable, and checking it for null before firing, such as
EventHandler myCustomEventCopy = MyCustomEvent;
if (myCustomEventCopy != null)
{
myCustomEventCopy (this, someArgs);
}
But this has a race-condition, i.e. handlers may fire even after they have unsubscribed from the event, which may corrupt the state of the application.
One solution that handles both problems is to initialize events to a blank handler, e.g.
public event EventHandler MyCustomEvent = delegate { };
and then fire them off without any checks, e.g.
MyCustomEvent(this, someArgs);
Edit: As others have pointed out, this is a complex issue.
http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx
Lippert points out that completely removing the "handler is fired after deregistration" problem requires that the handlers themselves are written in a robust manner.
An event at the bottom is MulticastDelegate, which is null if there is no method in the invocation list. Usually, you use a RaiseEvent() method to call an event, the pattern looks like the following:
public void RaiseEvent()
{
var handler = MyEvent;
if(handler != null)
handler(this, new EventArgs());
}
As you assign the event to a variable, it is threadsafe. You can miss a removed or added method though, which was added between the atomic operations (assignment -> null check -> invocation).
This is normal behaviour. The conventional pattern for throwing an event in .NET is to have a method called OnMyCustomEvent that you use to throw the event, like so:
protected void OnMyCustomEvent(MyCustomEventArgs e)
{
EventHandler<MyCustomEventArgs> threadSafeCopy = MyCustomEvent;
if (threadSafeCopy != null)
threadSafeCopy(this, e);
}
public event EventHandler<MyCustomEventArgs> MyCustomEvent;
Then from your code, you would call this.OnMyCustomEvent(someArgs) instead.
This is the normal behavior. To avoid this always test if there's an event subscriber before calling it:
if (MyCustomEvent != null)
{
MyCustomEvent(this, someArgs);
}
There is the "standard" approach of copying the reference and then checking for null (the value of the reference if no handlers are attached)—as given by other answers:
public EventHandler<MyEventArgs> MyEvent;
protected virtual OnMyEvent(MyEventArgs args) {
var copy = MyEvent;
if (copy != null) {
copy(this, args);
}
}
This works because, in part, MulticastDelegate instances are immutable.
There is another approach: the Null Object Pattern:
public EventHandler<MyEventArgs> MyEvent;
// In constructor:
MyEvent += (s,e) => {}; // No op, so it is always initialised
And there is no need to take a copy or check for null because it won't be. This works because there is no Clear method on an event.
Yes, you need to check for null. In fact, there's a right way to do it:
var myEvent = MyCustomEvent;
if (myEvent != null)
myEvent(this, someArgs);
This is the official right way because it avoids a possible race condition when the event is changed after the null check but before the call.

Why is this event declared with an anonymous delegate?

I have seen people define their events like this:
public event EventHandler<EventArgs> MyEvent = delegate{};
Can somebody explain how this is different from defining it without it? Is it to avoid checking for null when raising the event?
You got it - adding the empty delegate lets you avoid this:
public void DoSomething() {
if (MyEvent != null) // Unnecessary!
MyEvent(this, "foo");
}
This declaration ensures that MyEvent is never null, removing the tedious and error-prone task of having to check for null every time, at the cost of executing an extra empty delegate every time the event is fired.

C# Delegates and Events design help

I have some code in my project that saves an object to the database, once this is done I want it to call a series of other methods.
I was thinking about allowing other methods to subscribe to this event so I can add more as I need to. The idea I had for this was to create an array of Delegates allowing other methods to register, then when the object had been saved it could loop through the delegates and call each one.
Would this be bad practise or is there a better way of doing this?
Thanks
Event delegates are multicast, which means that they can hold references to more than one event handling method - see the MSDN documentation for Delegate and MulticastDelegate.
The syntax for subscribing to an event gives a clue:
MyEvent += MyHandler; // subscribe to an event
MyEvent -= MyHandler; // unsubscribe from an event
You can subscribe as many delegates as you want to a single event. Under the hood .Net keeps these as an ordered collection anyway.
The standard pattern for this is:
//in your class
public EventHandler<MyEvtArgs> MyEvent;
protected void OnMyEvent ( MyEvtArgs args ) {
if(MyEvent != null) //make sure there is at least 1 subscriber
MyEvent(this, args);
}
Then to call this:
var myInstance = new MyClass();
// all of these can convert to EventHandler<MyEvtArgs> (object, MyEvtArgs)
myInstance.MyEvent += (sender, e) => { /* do something 1 */ };
myInstance.MyEvent += (sender, e) => { /* do something 2 */ };
myInstance.MyEvent += localMethod;
Now when your protected OnMyEvent method is called inside your class all of these events will fire - in order.
You can also remove items from this collection:
myInstance.MyEvent -= localMethod;
You don't need an array. Just let anyone subscribe to one.
You can use a normal event for this. The runtime will handle looping over all fields.
public event EventHandler<EventArgs> WritingToDatabaseFinished;
protected void OnWritingToDatabaseFinished(EventArgs args)
{
EventHandler<EvetnArgs> handler = WritingToDatabaseFinished;
if (handler != null)
{
handler(this, args);
}
}
Your code calls
OnWritingToDatabaseFinished(args);
All methods that want to be informed have to register to the event:
WritingToDatabaseFinished += new EventHandler<EventArgs>(handlermethod);
Every handler that has been registered in the above way will be called when you call OnWritingToDatabaseFinished.
All you need is a multicast delegate. You don't need an array at all. You use += to add a reference to the delegate, and a -= to remove the reference.
I would recommend that you look at using a weak event handler instead. Take a look at this link to see why you'd use a weak event instead of a weak delegate.
Delegates are already multicast, so no need for a delegate array. Now, the recommended way of adding event support to your class is:
Add a public delegate (this will be your event handler)
public delegate void DatabaseEventHandler(object sender, DatabaseEventArgs e);
Add a public event, of your delegate type.
public event DatabaseEventHandler DatabaseDone;
Now, the event should send 2 parameters. The sender (this, usually), and the EventArgs. You should create a new class from System.EventArgs, and send the appropriate information within that class.

Categories

Resources