Assemblies

Assemblies are the building blocks of .NET Framework applications. They form the smallest unit of code distribution in the .NET Framework.

An assembly consists of one or more Win32 Portable Executable (PE) files. A Win32 PE file is built in a file format for executables that is common across all flavors of Windows. More information about PE file format (and the newer enhancements to it for 64-bit Windows) can be found in [Pie-02]. Each PE file within the assembly is referred to as a module.

An assembly can also contain auxiliary files such as HTML files, read-me files, and so on. Although an assembly may consist of multiple modules and auxiliary files, the assembly is named, versioned, and deployed as an atomic unit. For our current discussion, it is easier to view an assembly as a single executable file. This by far is the most common case for assemblies.

The .NET compilers can build an assembly either as a library file (with a typical filename extension .dll) or a stand-alone executable (extension .exe) file. Table 3.1 shows the compiler switches available with C# compiler (and most other .NET compilers) to build different types of assemblies.

Table 3.1. Assembly Type Compiler Switches
SwitchAssembly Type
-t:libraryLibrary
-t:exeConsole user interface (CUI) executable
-t:winexeGUI executable

An EXE-based assembly can be executed just as a standard stand-alone Win32 executable, for example, by entering the filename from a console window or by double-clicking the filename from Windows Explorer. A DLL-based assembly, on the other hand, is required to be loaded dynamically, either implicitly by the common language runtime or explicitly in your code.

To emulate the behavior of a stand-alone Win32 executable, an EXE-based assembly contains two additional pieces of information:

  1. It contains a small piece of bootstrapping code that points to CorExeMain, an API exported by the common language runtime. This function contains the logic to host the common language runtime. So, when the application is executed, the control is transferred to CorExeMain, which in turn loads the common language runtime into the process and transfers control over to it.

  2. It defines an entry point that the common language runtime can start executing code from. When we write code in a higher level language such as C#, the compiler automatically assumes that the entry point is a static method named Main.

Other than these two differences, both types of assemblies are treated similarly by the runtime. For example, an EXE-based assembly can just as easily be loaded dynamically, as illustrated in the following code excerpt:

// Project LoadAssembly

     public static void Main(String[] args) {
       Assembly a = Assembly.LoadFrom("ConsoleGreeting.exe");
       Console.WriteLine(a.FullName);
     }

The .NET Framework defines a class Assembly (namespace System.Reflection) to encapsulate an assembly. This class defines a static method, LoadFrom, to load an assembly given its filename. The preceding code loads an assembly named ConsoleGreeting.exe and outputs the display name of the assembly (property FullName). The display name of an assembly is the string representation of the identity of the assembly. The output from the program is shown here:

ConsoleGreeting, Version=1.2.3.4, Culture=neutral, PublicKeyToken=null

Let's see how we can interpret this identity of the assembly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.9.146