3

I decompiled an assembly using ILSpy, and one class in particular got my attention:

public class CustomTextStream : NetworkStream
{
    private EventHandler<CustomEventArgs> someEvent;
    public event EventHandler<CustomEventArgs> SomePublicEvent
    {
        add
        {
            EventHandler<CustomEventArgs> eventHandler = this.someEvent;
            EventHandler<CustomEventArgs> eventHandler2;
            do
            {
                eventHandler2 = eventHandler;
                EventHandler<CustomEventArgs> value2 = 
                    (EventHandler<CustomEventArgs>)Delegate.Combine(eventHandler2, value);
                eventHandler = 
                    Interlocked.CompareExchange<EventHandler<CustomEventArgs>>(
                    ref this.someEvent, value2, eventHandler2);
            }
            while (eventHandler != eventHandler2);
        }
        remove
        {
            // similar stuff...
        }
    }
}

Further in the code, seems like private delegate is used to fire an actual event:

if (something != null && somethingElse != 0)
{
    this.someEvent(this, new CustomEventArgs(someArg));
}

The question: Can someone guess what could be the idea behind this custom accessors, assuming that some "compile/decompile magic" didn't take place? I'm not much familiar with IL, btw...

(Side note: the application is multi-threaded and utilizes networking, obviously.)

Less
  • 3,047
  • 3
  • 35
  • 46
  • Looks like default code at first glance - the normal "event" is actually something close to this code. Consider trying to create code with an event and than decompile. – Alexei Levenkov Mar 26 '13 at 19:58
  • 1
    i saw strange stuff like this generated by obfuscators just to confuse you. – NickD Mar 26 '13 at 19:58
  • @Alexei Levenkov I already did that. I didn't get the same results. The only thing in a "normal" decompiled event is `Delegate.Combine()` part – Less Mar 26 '13 at 19:59
  • @Snoopy this thought also entered my mind :) It's actually quite possible that this is the obfuscation result – Less Mar 26 '13 at 20:01
  • 2
    It is just the default code that the C# v4+ compiler generates when you **don't** write your own add/remove accessors. Just write `public event EventHandler foo;` and look at it with a disassembler. – Hans Passant Mar 26 '13 at 20:02
  • @Hans Passant yeah, I already did that, but got pretty different results. I used VS2008 .net 3.5 - don't really know which compiler version is that – Less Mar 26 '13 at 20:41

1 Answers1

9

This is a new event handler code generated by compiler. It was introduced in C# 4 (C# 3 version was different)

Interlocked.CompareExchange compares first argument with third, and if they are equal, replaces first argument with second. This is a thread-safe operation. Loop is used for a case when after assigning a variable eventHandler2 and before check, another thread changes this delegate. In this case, Interlocked.CompareExchange does not perform exchange, loop condition does not evaluate to true and next attempt is made.

C# 3 generated simple code in event handlers:

add { lock(this) { changed = changed + value; } }

Which had lower performance and could introduce deadlocks.

There is a great series of articles on this subject:

Events get a little overhaul in C# 4

Events get a little overhaul in C# 4, Part II

Alexander
  • 4,153
  • 1
  • 24
  • 37