C# allows wrapping method group into delegate constructor. That disable delegate caching and construct new delegate instance on each invocation. That distinction visible in IL but lost in C# decompilation.
Input code
using System;
static class Test
{
static Action Test1() => M;
static Action Test2() => new(M);
static void M() {}
}
Erroneous output
using System;
internal static class Test
{
private static Action Test1()
{
return M;
}
private static Action Test2()
{
return M;
}
private static void M()
{
}
}
.class private auto ansi abstract sealed beforefieldinit Test
extends [System.Runtime]System.Object
{
// Nested Types
.class nested private auto ansi abstract sealed beforefieldinit '<>O'
extends [System.Runtime]System.Object
{
.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Fields
.field public static class [System.Runtime]System.Action '<0>__M'
} // end of class <>O
// Methods
.method private hidebysig static
class [System.Runtime]System.Action Test1 () cil managed
{
// Method begins at RVA 0x2050
// Header size: 1
// Code size: 28 (0x1c)
.maxstack 8
// sequence point: (line 5, col 27) to (line 5, col 28) in M:\Temp\Test\Test.cs
IL_0000: ldsfld class [System.Runtime]System.Action Test/'<>O'::'<0>__M'
IL_0005: dup
IL_0006: brtrue.s IL_001b
IL_0008: pop
IL_0009: ldnull
IL_000a: ldftn void Test::M()
IL_0010: newobj instance void [System.Runtime]System.Action::.ctor(object, native int)
IL_0015: dup
IL_0016: stsfld class [System.Runtime]System.Action Test/'<>O'::'<0>__M'
IL_001b: ret
} // end of method Test::Test1
.method private hidebysig static
class [System.Runtime]System.Action Test2 () cil managed
{
// Method begins at RVA 0x206d
// Header size: 1
// Code size: 13 (0xd)
.maxstack 8
// sequence point: (line 6, col 27) to (line 6, col 33) in M:\Temp\Test\Test.cs
IL_0000: ldnull
IL_0001: ldftn void Test::M()
IL_0007: newobj instance void [System.Runtime]System.Action::.ctor(object, native int)
IL_000c: ret
} // end of method Test::Test2
.method private hidebysig static
void M () cil managed
{
// Method begins at RVA 0x207b
// Header size: 1
// Code size: 2 (0x2)
.maxstack 8
// sequence point: (line 7, col 18) to (line 7, col 19) in M:\Temp\Test\Test.cs
IL_0000: nop
// sequence point: (line 7, col 19) to (line 7, col 20) in M:\Temp\Test\Test.cs
IL_0001: ret
} // end of method Test::M
} // end of class Test
Details
- Product in use: ILSpy
- ILSpy version: 10.1.1.8388+1377eb6e7351b21112858c8c1df39848f40181ec
- .NET version: 10.0.10-servicing.26326.116+f7d90799ce4ef09a0bb257852a57248d2a8fb8dd
C# allows wrapping method group into delegate constructor. That disable delegate caching and construct new delegate instance on each invocation. That distinction visible in IL but lost in C# decompilation.
Input code
Erroneous output
Details