Are event handlers fired in the order that they attached to the event? If not, can I enforce some kind of order onto the event handlers such that they are called in a specif
Assuming a simple implementation of the event (using += and -= on a delegate field, which in turn will use Delegate.Combine/Remove
) then yes, the event handlers will be called in the order in which they're subscribed. The guarantee is effectively given in the Delegate.Combine documentation:
Return value
A new multicast (combinable) delegate with an invocation list that concatenates the invocation lists of a and b in that order.
See my article about events for some examples of which Delegate.Combine/Remove
do (and what events are like under the covers).
Do NOT rely on event ordering. All event dispatches should be logically independent, as if they were occurring in parallel.
The addition of event handlers in other classes and threads may disturb your assumed ordering, this is just not a safe assumption to make, and it goes against the concept of events as independent decoupled actions.
I'll go one step further, and assert that if you have to assume an order for events firing, you have a serious design flaw and/or are misusing events.
You might have one event handler that calls other functions or delegates in a specified order.
I would recommend "wrapping it."
Do something like this...
MyObject.MyEvent += new MyEventHandler(Wrapper);
public void Wrapper()
{
Method1();
Method3();
Method2();
}
That way you're still hooking the event but have complete control of what's called.
Sorry for the late reply.
I've come across with a situation that I have to deal with order of eventhandlers.
I have a form, and when I click a button on the form, a object is added into a collection somewhere in my code.
The collection has a "Added" event, and two delegates have been hooked to it. One of the method deletes any item just added into the collection, while the other one shows message to user.
If I have some code shows here, a "IndexOutOfRange" exception would be thrown when the event is triggered:
// this methods hooks two delegates to MyCollection.Added event, but the order results in a "IndexOutOfRange" exception after the event is triggered
HookEvents()
{
MyCollection.Added += new CollectionItemAddedHandler(DeleteItem_After_CollectionItemAdded);
MyCollection.Added += new CollectionItemAddedHandler(ShowMessage_After_CollectionItemAdded);
}
// when user click a button on form, add a object to MyCollection
Button_Clicked()
{
MyCollection.Add(new object());
}
// at the moment a object is added into the collection, this method remove it
DeleteItem_After_CollectionItemAdded(NewIndexArgs e)
{
MyCollection.Remove(e.NewIndex); // e.NewIndex represents the newly added item index in current collection
}
// at the moment a object is added into the collection, this method show its information (hey, but remember, I just remove it in the previous method)
ShowMessage_After_CollectionItemAdded(NewIndexArgs e)
{
MessageBox.Show(MyCollection[e.NewIndex]); // tell user what is just added into the current collection
// a "IndexOutOfRange" exception is thrown here....
}
What will make this scenario work correctly is that the "ShowMessage_After_CollectionItemAdded" method should be triggered first, and then it'd be the "DeleteItem_After_CollectionAdded" method.
Although we can += the "ShowMessage..." method first, there's sometimes we can't predefine this sequence until runtime.