If I register for an event in c# while it's dispatching, am I guaranteed to not get called again during that dispatch?
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
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 :)