Today I learned that the + operator cannot be passed a delegate. I get
an error from the CLR saying I have an invalid program.
Congratulations, you've discovered a bug! Step right up to Microsoft Connect
to earn your prize...
With that, I was wondering if someone could tell me what other types I
am not allowed to make parameters.
It's not that, the compiler is emitting invalid IL, and the CLR barfs when
it encounters it.
class Failer
{
public static Failer operator +(Failer failer,
MulticastDelegate handler)
{
return failer;
}
public static void Test()
{
Failer failer = new Failer();
object o = failer + new EventHandler(
delegate(object sender, EventArgs e)
{
// DO NOTHING
});
}
}
Change this to
object o = failer + delegate...
That is, simply omit the explicit instantiation, and it will work. It will
also work if you use a method rather than an anonymous delegate. Your
original code is failing because it compiles to something like this:
..method public hidebysig static void Test() cil managed
{
// Code size 15 (0xf)
.maxstack 1
.locals init ([0] class ConsoleApplication2.Failer failer,
[1] object o)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication2.Failer::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call class ConsoleApplication2.Failer
ConsoleApplication2.Failer:
p_Addition(class ConsoleApplication2.Failer,
class [mscorlib]System.EventHandler)
IL_000d: stloc.1
IL_000e: ret
} // end of method Failer::Test
The call at IL_0008 is invalid because there's only one argument on the
stack as opposed to the two which are required. There's something going
wrong here with the magic the compiler uses to create event handlers from
delegates -- the required code is completely missing!
The corrected code looks like this:
..method public hidebysig static void Test() cil managed
{
// Code size 46 (0x2e)
.maxstack 4
.locals init ([0] class ConsoleApplication2.Failer failer,
[1] object o)
IL_0000: nop
IL_0001: newobj instance void ConsoleApplication2.Failer::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: ldsfld class [mscorlib]System.EventHandler
ConsoleApplication2.Failer::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_000d: brtrue.s IL_0022
IL_000f: ldnull
IL_0010: ldftn void ConsoleApplication2.Failer::'<Test>b__0'(object,
class
[mscorlib]System.EventArgs)
IL_0016: newobj instance void
[mscorlib]System.EventHandler::.ctor(object,
native int)
IL_001b: stsfld class [mscorlib]System.EventHandler
ConsoleApplication2.Failer::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0020: br.s IL_0022
IL_0022: ldsfld class [mscorlib]System.EventHandler
ConsoleApplication2.Failer::'CS$<>9__CachedAnonymousMethodDelegate1'
IL_0027: call class ConsoleApplication2.Failer
ConsoleApplication2.Failer:
p_Addition(class ConsoleApplication2.Failer,
class [mscorlib]System.EventHandler)
IL_002c: stloc.1
IL_002d: ret
} // end of method Failer::Test
You see the boilerplate here between IL_0008 and IL_0022 for creating your
event handler and loading it from a static field.