In classic Win32 development environments, such as Visual Basic 6 or Visual C++, your
source code is parsed by compilers that produce binary executable files that can be immediately interpreted and run by the operating system. This affects both standalone applications and dynamic/type libraries. Actually Win32 applications, built with Visual Basic 6 and C++, used a runtime, but if you had applications developed with different programming languages, you also had to install the appropriate runtimes. In.NET development things are quite different. Whatever .NET language you create applications with, compilers
generate an assembly, which is a file containing .NET executable code and is composed
essentially by two kinds of elements: MSIL code and metadata. MSIL stands for Microsoft
Intermediate Language and is a high-level assembly programming language that is also
object-oriented, providing a set of instructions that are CPU-independent (rather than
building executables that implement CPU-dependent sets of instructions). MSIL is a
common language in the sense that the same programming tasks written with different
.NET languages produce the same IL code. Metadata is instead a set of information related
to the types implemented in the code. Such information can contain signatures, functions
and procedures, members in types, and members in externally referenced types. Basically
metadata’s purpose is describing the code to the .NET Framework. Obviously, although an
assembly can have .exe extension, due to the described structure, it cannot be directly
executed by the operating system. In fact, when you run a .NET application the operating
system can recognize it as a .NET assembly (because between .NET and Windows there is a
strict cooperation) and invoke the Just-In-Time compiler.
The Execution Process and the Just-In-Time (JIT) Compiler
.NET compilers produce assemblies that store IL code and metadata. When you launch an
assembly for execution, the .NET Framework packages all the information and translates
them into an executable that the operating system can understand and run. This task is
the responsibility of the Just-In-Time (JIT)compiler. JIT compiles code on-the-fly just
before its execution and keeps the compiled code ready for execution. It acts at the
method level. This means that it first searches for the application’s entry point (typically
the Sub Main) and then compiles other procedures or functions (methodsin .NET terminology) referenced and invoked by the entry point and so on, just before the code is
executed. If you have some code defined inside external assemblies, just before the
method is executed the JIT compiler loads the assembly in memory and then compiles the
code. Of course loading an external assembly in memory could require some time and
affect performance, but it can be a good idea to place seldom-used methods inside external assemblies, the same way as it could be a good idea to place seldom-used code inside
separated methods.