Here is the generated MSIL code from ILSpy.
As we see, the local method is converted as being like any instance method of the current class and the code only exists once.
Thus the compiler "refactor" itself.
C# local methods are not like C and C ++ inline functions whose code is repeated according to usage.
Local methods allow to refactor the code and to create a more clean code while disallowing the call from the exterior of the method containing them, to segregate processings and/or to call them several times.
There is also previously available the local lambdas using Action and Func.
Also the delegate, being the ancestor of all.
Local functions (C# Programming Guide)
.method public hidebysig static bool Test (int32[] args) cil managed
{
.param [1]
.custom instance void [mscorlib]System.ParamArrayAttribute::.ctor() = (01 00 00 00)
.maxstack 2
.locals init (
[0] int32[],
[1] int32,
[2] int32 n,
[3] bool,
[4] bool
)
// foreach (int i2 in args)
// {
// if (!isNumberValid(i2))
// {
// return false;
// }
// }
IL_0003: ldarg.0
// (no C# code)
IL_0004: stloc.0
IL_0005: ldc.i4.0
IL_0006: stloc.1
IL_0007: br.s IL_0026
// loop start (head: IL_0026)
IL_0009: ldloc.0
IL_000a: ldloc.1
IL_000b: ldelem.i4
IL_000c: stloc.2
// if (!isNumberValid(i2))
IL_000e: ldloc.2
>>>>>>>>>>
IL_000f: call bool ConsoleApp.Program::'<Test>g__isNumberValid|30_0'(int32)
>>>>>>>>>>
IL_0014: ldc.i4.0
IL_0015: ceq
IL_0017: stloc.3
IL_0018: ldloc.3
// (no C# code)
IL_0019: brfalse.s IL_0021
// return false;
IL_001c: ldc.i4.0
IL_001d: stloc.s 4
// (no C# code)
IL_001f: br.s IL_0031
IL_0022: ldloc.1
IL_0023: ldc.i4.1
IL_0024: add
IL_0025: stloc.1
IL_0026: ldloc.1
IL_0027: ldloc.0
IL_0028: ldlen
IL_0029: conv.i4
IL_002a: blt.s IL_0009
// end loop
// return true;
IL_002c: ldc.i4.1
IL_002d: stloc.s 4
// (no C# code)
IL_002f: br.s IL_0031
IL_0031: ldloc.s 4
IL_0033: ret
} // end of method Program::Test
Here is the local method now being a class method:
.method assembly hidebysig static bool '<Test>g__isNumberValid|30_0' (int32 i) cil managed
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor()
= (01 00 00 00)
// Method begins at RVA 0x342c
// Code size 10 (0xa)
.maxstack 2
.locals init (
[0] bool
)
// return i > 0;
IL_0001: ldarg.0
IL_0002: ldc.i4.0
IL_0003: cgt
IL_0005: stloc.0
// (no C# code)
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method Program::'<Test>g__isNumberValid|30_0'