tags:

views:

711

answers:

1

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
+5  A: 

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 :)

Jon Skeet
So basically, calling TestEvent instantiates a delegate invocation list that is immutable. And adding a delegate creates another invocation list. So you can never attach another method to the end of a currently executing list.
toast