8

Is there a way to specify an order or priority to handle registered event delegates? For example, I have an event that I would like processed immediately before any other events, but I want other objects to be allowed to register listeners to the event as well. How can this be accomplished?

Lets say I want proc1 to always run before proc 2.

class MessageProcessor
{
    private DataClient Client;
    public MessageProcesser(DataClient dc)
    {
         Client = dc;
         Client.MessageReceived += ProcessMessage;
    }

    void proc1(MessageEventArgs e)
    {
        // Process Message
    }

}

class DataClient
{
    public event MessageReceievedHandler MessageReceived;
}

void main()
{
    DataClient dc = new DataClient();
    MessageProcessor syncProcessor = new MessageProcessor(dc); // This one is high priority and needs to process all sync immediately when they arrive before any data messages
    MessageProcessor dataProcessor= new MessageProcessor(dc);  // This one can process the data as it has time when sync messages are not being processed.

    // do other stuff

}

The reason for doing this, I have a server that is sending messages over a UDP stream. It will send sync messages before a burst of data. I realize both handlers will fire when a sync message is received, but to decrease latency I would like the syncProcessor objects events processed before the dataProcessor events. This would decrease the latency of the Sync Message being processed.

In addition, someone else on my team may want to register events to process specific messages also. They may have their own object that will register an event (May not be MessageProcessor), even still the Sync message should have as low latency as possible.

EDIT Made the objective more clear with a better example.

galford13x
  • 2,483
  • 4
  • 30
  • 39
  • Queue up the MessageEventArgs in the handlers, then kick off a method that implemements priority and dependancy. This a bugfest you know, I'd be having a heated conversation with myself before I tried to not make this fail too often. – Tony Hopkinson Mar 08 '12 at 18:34
  • I was put the example just for simplicity as I realize in this case registering both events within the same resource/object is pointless. I'll change my setup to more accurately represent my goal. – galford13x Mar 08 '12 at 18:34
  • @Tony: Interesting Idea. I agree this could enter a realm of issues. I was actually thinking of creating an interface, when someone registered an event, the DataClient would register it, but have a priority mapping object that when a message was received it would call off the events in the handler in the defined order. but this too seemed like a bad path to go down. – galford13x Mar 08 '12 at 18:37
  • @galford13x, that's doable and yes problematic. Seems to me you are trying to bend the multiple event handler model into a set of cooperating processes, at best that's going to be a bodge, worse still it's going to be horribly fragile. – Tony Hopkinson Mar 09 '12 at 09:41

4 Answers4

6

When you subscribe to an event multiple times, there is no possible way to be sure of the execution order of your handlers when the event is fired.

According to this answer, the order in the subscription order, but as the post author said, it's an implementation detail and you must not rely on it.

You could of course write your own "event manager" (see dirty example below) that executes your handlers in a known order, but I don't think it would be a good idea. Maybe you should re-design your event to remove your requirement.

public class MyClass
{    
    // Could be anything...
    public delegate void MyEventHandler(object sender, EventArgs e);

    public event MyEventHandler TestEvent;

    public void Test()
    {
        if (this.TestEvent != null)
        {
            this.TestEvent(this, EventArgs.Empty);
        }
    }
}

public class EventManager
{
    private List<EventHandler> Handlers = new List<EventHandler>();

    public void AddHandler(EventHandler handler)
    {
        this.Handlers.Add(handler);
    }

    public void RemoveHandler(EventHandler handler)
    {
        this.Handlers.Remove(handler);
    }

    public void Handler(object sender, EventArgs e)
    {
        foreach (var z in this.Handlers)
        {
            z.Invoke(sender, e);
        }
    }
}

private static void Main(string[] args)
{
    MyClass test = new MyClass();

    EventManager eventManager = new EventManager();

    // Subscribes to the event
    test.TestEvent += eventManager.Handler;

    // Adds two handlers in a known order
    eventManager.AddHandler(Handler1);
    eventManager.AddHandler(Handler2);

    test.Test();

    Console.ReadKey();
}

private static void Handler1(object sender, EventArgs e)
{
    Console.WriteLine("1");
}

private static void Handler2(object sender, EventArgs e)
{
    Console.WriteLine("2");
}
Community
  • 1
  • 1
ken2k
  • 48,145
  • 10
  • 116
  • 176
  • +1: This example is similar to what I was planning to do. But I too thought it a bad path to go down. I was aiming for a solution built into .net. – galford13x Mar 08 '12 at 18:50
1

In this case, you are better off simply calling the second event at the end of the first event, etc.

1

If this is your own event that you defined, then your best bet might be to extend it to have a BeforeMessageReceived, MessageReceived and AfterMessageReceived events. (okay, so maybe MessageProcessed would be a better root, since you can know before a message is received).

This will give you more control over exactly where different event handlers occur.

You see the same before, event, after patten all over the place.

Matt Burland
  • 44,552
  • 18
  • 99
  • 171
0

Im going to go out on a limb and say no. AFAIK events are dispatched ASYNCHRONOUSLY by nature. So that will be dispatched in the order they are bound. however the results may return in a different order. The only way would be to dispatch your 2nd event inside the callback for the first event. This is not language specific, just more on the architecture of events.

In your example since the calls are void y not run proc2 at the end of proc1?

j_mcnally
  • 6,928
  • 2
  • 31
  • 46
  • 1
    the events are dispatched asynchronously? I thought they are all dispatched on the same thread which would of course make them synchronous. I assume you mean they are dispatched in no defined order? If they are always dispatched in the order they are bound, then I could accomplish my goal by ensuring that the highest priority event is registered first? – galford13x Mar 08 '12 at 18:52
  • so your saying the entire thread sleeps when an event is dispatched? What if nothing is bound to the event. The app would wait indefinitely. That is why I think its asynchronous at that point? no? – j_mcnally Mar 08 '12 at 23:36
  • if you need it to happen syncronously you should call function 2 from function 1 where function 1 is the event handler. Otherwise you will be creating a race condition. This is how every other event model in the world exists. I am 99% positive its how it works in C# – j_mcnally Mar 08 '12 at 23:40
  • The point of events is to decouple interaction from your code. Basically you could dispatch and event and forget about it, if somethings listening it will act appropriately, if not, who cares. – j_mcnally Mar 08 '12 at 23:46
  • 1
    I don't say the thread sleep when an event is dispatched. For instance if you press a button then the event that executes the button press is executed on the same thread that the button exists on which would be the GUI thread. So if two buttons are pressed at the same time, one event cannot execute until the previous has completed. That is what I meant by they are not asynchronous. Events will be executed on the thread they are bound to. – galford13x Mar 09 '12 at 21:56
  • 1
    Events are multicast delegates. When you fire an event you are just calling all the methods registered with the event on the same thread. If there are no methods (handlers) registered, nothing happens (actually, you get an NRE) – angelsl Sep 04 '15 at 09:21
  • -1 This is not an answer, it is an uneducated guess that is, along with the followon comments by its author, completely wrong. C# events are simply a list of callback functions, and calling an event calls each function in turn ... there is nothing remotely asynchronous about it, there is no thread sleep, there is no decoupling of interaction from your code ... events can *return values* (however, all but the last return value is ignored). – Jim Balter Mar 22 '16 at 02:02