How and when does .NET actually compile code?

2020-02-08 09:15发布

问题:

Let's say you write an app in C#, VB, anything with .NET When you hit build, does it really compile your code? I thought so until I started using redgates reflector on some of my assemblies and saw my code verbatim. I would have expected loops to be unrolled and another plethora of optimizations, instead nothing.

So when does the compilation actually happen? I think when it is built, code become IL (Intermediary Language) and when execution occurs, it is loading in the CLR? Is it optimized during CLR only and never at build time?

回答1:

When you compile in VS

  1. Your source code is compiled into a byte code known as the common intermediate language (CIL) or MSIL (Microsoft Intermediate Language).
  2. Metadata from every class and every methods (and every other thing :O) is included in the PE header of the resulting executable (be it a dll or an exe).
  3. If you're producing an executable the PE Header also includes a conventional bootstrapper which is in charge of loading the CLR (Common language runtime) when you execute you executable.

When you execute:

  1. The bootstraper initializes the CLR (mainly by loading the mscorlib assembly) and instructs it to execute your assembly.
  2. The CLR executes your main entry.
  3. Now, classes have a vector table which hold the addresses of the method functions, so that when you call MyMethod, this table is searched and then a corresponding call to the address is made. Upon start ALL entries for all tables have the address of the JIT compiler.
  4. When a call to one of such method is made, the JIT is invoked instead of the actual method and takes control. The JIT then compiles the CIL code into actual assembly code for the appropiate architecture.
  5. Once the code is compiled the JIT goes into the method vector table and replaces the address with the one of the compiled code, so that every subsequent call no longer invokes the JIT.
  6. Finally, the JIT handles the execution to the compiled code.
  7. If you call another method which haven't yet being compiled then go back to 4... and so on...

I post the answer here too as the other question was not really about this...



回答2:

It is compiled down to IL at, well, compile time. Reflector's magic is that it "understands" the IL and converts it back into c# (or VB.NET or whatever. Look under the Options menu in Reflector and you can view the assembly in any format, including the IL).

In Reflector, you actually are not seeing your original code. You are seeing a translation of the IL into c#. Most of the time that will be very similar to what you wrote, but there are some telltale signs - for example, find a place where you implemented an auto-property:

string MyProperty {get;set;}

And you'll see what that actually compiles to, which is something like this:

public string MyProperty
{
    [CompilerGenerated]
    get
    {
        return this.<MyProperty>k__BackingField;
    }
    [CompilerGenerated]
    set
    {
        this.<MyProperty>k__BackingField = value;
    }
}