If I register for an event in c# while it's dispatching, am I guaranteed to not get called again during that dispatch?

StackOverflow https://stackoverflow.com/questions/141423

  •  02-07-2019
  •  | 
  •  

Question

In C#, I find myself occasionally wanting to register a method for an event in the middle of a dispatch of that same event. For example, if I have a class that transitions states based on successive dispatches of the same event, I might want the first state's handler to unregister itself and register the second handler. However, I don't want the second handler to be dispatched until the next time the event is fired.

The good news is that it looks like the Microsoft implementation of C# behaves exactly this way. The event registration syntax sugar gets replaced with a call to System.Delegate.Combine, which just concatenates the current invocation list and the new method into a separate list and assigns it to the event property. This gives me exactly the behavior I want.

So, my question is: is this guaranteed behavior by the language standard? I like to be able to run my C# code on other platforms under mono and generally want to make sure I'm not making assumptions about the language standard based on its implementation.

I couldn't find any definitive information on MSDN.

If you'd like a specific example of what I'm talking about, here's an example:

    delegate void TestDelegate();
    static event TestDelegate TestEvent;

    static void Main (string[] args) {
        TestEvent += TestDelegateInstanceFirst;
        TestEvent();
        TestEvent();
    }

    static void TestDelegateInstanceFirst () {
        Console.WriteLine("First");
        TestEvent += TestDelegateInstanceSecond;
    }

    static void TestDelegateInstanceSecond () {
        Console.WriteLine("Second");
    }

At least on Windows, the output is:

First
First
Second
Was it helpful?

Solution

Yes, it's guaranteed.

From the unified C# 3.0 spec, section 15.1:

However, when two non-null delegate instances are combined, their invocation lists are concatenated—in the order left operand then right operand—to form a new invocation list, which contains two or more entries.

Note the "new invocation list". And again in section 15.3:

Once instantiated, delegate instances always refer to the same target object and method. Remember, when two delegates are combined, or one is removed from another, a new delegate results with its own invocation list; the invocation lists of the delegates combined or removed remain unchanged.

Finally, MSDN for System.Delegate states:

Delegates are immutable; once created, the invocation list of a delegate does not change.

I suspect there's something in the CLI spec - I'll check if you'd like, but hopefully these three have given you enough confidence :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top