C#编译生成IL中IL_0000分配的作用及Func<int32>与DisplayClass的关联
Great questions! Let's start by laying out the code context clearly, then dive into each question one by one.
static void Main(string[] args) { int val = int.Parse(Console.ReadLine()); Do(() => { if (val == 0) return 1; return 42; }); } public static int Do(Func<int> query) { return query(); }
Main .method private hidebysig static void Main( string[] args ) cil managed { .entrypoint .maxstack 8 IL_0000: newobj instance void ConsoleApp1.Program/'<>c__DisplayClass0_0'::.ctor() // [30 13 - 30 53] IL_0005: dup IL_0006: call string [System.Console]System.Console::ReadLine() IL_000b: call int32 [System.Runtime]System.Int32::Parse(string) IL_0010: stfld int32 ConsoleApp1.Program/'<>c__DisplayClass0_0'::val // [31 13 - 36 16] IL_0015: ldftn instance int32 ConsoleApp1.Program/'<>c__DisplayClass0_0'::'<Main>b__0'() IL_001b: newobj instance void class [System.Runtime]System.Func`1<int32>::.ctor(object, native int) IL_0020: call int32 ConsoleApp1.Program::Do(class [System.Runtime]System.Func`1<int32>) IL_0025: pop // [39 9 - 39 10] IL_0026: ret } // end of method Program::Main
1. What's the purpose of the allocation at IL_0000?
That allocation creates an instance of the compiler-generated <>c__DisplayClass0_0 type—this is how C# handles closures. Your lambda expression references the local variable val from the Main method. Since lambdas can potentially outlive the scope of the method where they're defined (even if not in this specific case), the compiler can't keep val on the stack. Instead, it wraps the variable in a class (the "display class") so the lambda can access it as an instance field.
The steps right after this allocation reinforce this:
IL_0005: dupkeeps a reference to the display class instance on the stack- After parsing the input to get
val,IL_0010: stfldstores that value into thevalfield of the display class instance.
2. How is the association between Func<int32> and the DisplayClass established? Is it via IL_0015 and IL_001b?
You're exactly right—those two instructions are what tie everything together:
IL_0015: ldftnloads the method address of the compiler-generated<Main>b__0method. This method is the actual implementation of your lambda (it checks thevalfield of the display class and returns 1 or 42).IL_001b: newobjcreates a newFunc<int>instance. TheFunc<T>constructor takes two parameters:- The target object (the display class instance we created earlier, which is still on the stack from the
dupat IL_0005) - The method address we just loaded with
ldftn
- The target object (the display class instance we created earlier, which is still on the stack from the
This binds the Func<int> to both the display class instance (so it can access the val field) and the lambda's implementation method. When Do calls query(), it's invoking that <Main>b__0 method on the display class instance.
内容的提问来源于stack exchange,提问作者Lou

