When source code written in a CLR-based language is compiled, two things are produced: instructions expressed in Microsoft Intermediate Language (MSIL), and metadata, information about those instructions and the data they manipulate. Whether this code is initially written in C#, VB, or some other CLR-based language, the compiler transforms all of the types it containsclasses, structs, integers, delegates, and all the restinto MSIL and metadata.
Figure 2-4 illustrates this process. In this example, the code being compiled contains three CTS types, all of them classes. When this code is compiled using whatever compiler is appropriate for the language it's written in, the result is an equivalent set of MSIL code for each class along with metadata describing those classes. Both the MSIL and the metadata are stored in a standard Windows portable executable (PE) file. This file can be either a DLL or an EXE, with the general term module sometimes used to mean either of these. This section takes a closer look at MSIL and metadata. Figure 2-4. Compiling managed code written in any language produces MSIL and metadata describing that MSIL.
Microsoft Intermediate Language (MSIL)
MSIL is quite similar to a processor's native instruction set. However, no hardware that actually executes these instructions (today, at least) is available. Instead, MSIL code is always translated into native code for whatever processor this code is running on before it's executed. It's probably fair to say that a developer working in the .NET Framework environment need never fully understand MSIL. Nevertheless, it's worth knowing at least a little bit about what a compiler produces from code written in C# or VB or any other CLR-based language.
As implied earlier in this chapter, the abstract machine defined by the CLR is stack based, which means that many MSIL operations are defined in terms of this stack. Here are a few example MSIL instructions and what they're used for:
In effect, MSIL is the assembly language of the CLR. One interesting thing to notice about this tiny sample of the MSIL instruction set is how closely it maps to the abstractions of the CLR's CTS. Objects, value types, and even boxing and unboxing all have direct support. Also, some operations, such as the newobj used to create new instances, are analogous to operators more commonly found in high-level languages than they are to typical machine instructions.
For developers who wish to work directly in this low-level argot, the .NET Framework provides an MSIL assembler called Ilasm. Only the most masochistic developers are likely to use this tool, however, or those who need very low-level control. Why write in MSIL when you can use a simpler, more powerful language such as VB or C# and get the same result? MetadataCompiling managed code always produces MSIL. Compiling managed code also always produces metadata describing that code. Metadata is information about the types defined in the managed code it's associated with, and it's stored in the same file as the MSIL generated from those types. Figure 2-5 shows an abstract view of a module produced by a CLR-based compiler. The file contains the MSIL code generated from the types in the original program, which once again are the three classes X, Y, and Z. Along with the code for the methods in each class, the file contains metadata describing these classes and any other types defined in this file. This information is loaded into memory when the file itself is loaded, making the metadata accessible at runtime. Metadata can also be read directly from the file that contains it, making information available even when code isn't loaded into memory. The process of reading metadata is known as reflection, and it's described in a bit more detail in Chapter 4. Figure 2-5. A module contains metadata for each type in the file.
What Metadata ContainsMetadata describes the types contained in a module. Among the information it stores for a type are the following things:
More detailed information is also available. For example, the description of each method includes the method's parameters and their types, along with the type of the method's return value. Because metadata is always present, tools can rely on it always being available. Visual Studio, for example, uses metadata to provide IntelliSense, which shows a developer things like what methods are available for the class name she's just typed. A module's metadata can also be examined using the MSIL disassembler tool, commonly referred to as Ildasm. This tool is the reverse of the Ilasm tool mentioned earlier in this chapterit's a disassembler for MSILand it can also provide a detailed display of the metadata contained in a particular module.
AttributesMetadata also includes attributes. Attributes are values that are stored in the metadata and can be read and used to control various aspects of how this code executes. Attributes can be added to types, such as classes, and to fields, methods, and properties of those types. As described later in this book, the .NET Framework class library relies on attributes for many things, including specifying transaction requirements, indicating which methods should be exposed as SOAP-callable Web services, and describing security requirements. These attributes have standard names and functions defined by the various parts of the .NET Framework class library that use them.
Developers can also create custom attributes used to control behavior in an application-specific way. To create a custom attribute, a developer using a CLR-based programming language such as C# or VB can define a class that inherits from System.Attribute. An instance of the resulting class will automatically have its value stored in metadata when it is compiled.
|