In addition to execution instructions, CIL code includes metadata about the types and files included in a program. The metadata includes the following items:
The metadata is not a cursory, nonessential add-on to the CIL, but rather represents a core component of the CLI implementation. It provides the representation and the behavior information about a type and includes location information about which assembly contains a particular type definition. It plays a key role in saving data from the compiler and making it accessible at execution time to debuggers and the runtime. This data not only is available in the CIL code but also is accessible during machine code execution so that the runtime can continue to make any necessary type checks.
Metadata provides a mechanism for the runtime to handle a mixture of native and managed code execution. Also, it increases code and execution robustness because it smooths the migration from one library version to the next, replacing compile-time–defined binding with a load-time implementation.
All header information about a library and its dependencies is found in a portion of the metadata known as the manifest. As a result, the manifest portion of the metadata enables developers to determine a module’s dependencies, including information about particular versions of the dependencies and signatures indicating who created the module. At execution time, the runtime uses the manifest to determine which dependent libraries to load, whether the libraries or the main program has been tampered with, and whether assemblies are missing.
The metadata also contains custom attributes that may decorate the code. Attributes provide additional metadata about CIL instructions that are accessible via the program at execution time.
Metadata is available at execution time by a mechanism known as reflection. With reflection, it is possible to look up a type or its member at execution time and then invoke that member or determine whether a construct is decorated with a particular attribute. This provides for late binding, in which the system determines which code to execute at execution time rather than at compile time. Reflection can even be used for generating documentation by iterating through metadata and copying it into a help document of some kind (see Chapter 18).
The .NET Native feature creates a platform-specific executable. This is referred to as ahead of time (AOT) compilation.
.NET Native allows programmers to continue to code in C# while achieving native code performance and faster startup times by eliminating the need to JIT compile code. When .NET Native compiles an application, the .NET FCL is statically linked to the application; .NET Framework runtime components optimized for static pre-compilation are included as well. These specially built components are optimized for .NET Native and provide improved performance over the standard .NET runtime. The compilation step does not change your application in any way. You are free to use all the constructs and APIs of .NET, as well as depend on managed memory and memory cleanup, since .NET Native will include all components of the .NET Framework in your executable.