Assemblies

Assemblies are usually created using the C# compiler; however, Assembly Linker (al.exe) might be required under certain circumstances. We demonstrate one area where the assembly linker is required later in this chapter in Creating a Multifile Assembly.

The format of an assembly governs how it can be used; for example, the exe and winexe formats are executable but cannot be imported as references to other assemblies. The format of an assembly is specified using the /target:<format> switch on the C# compiler and the assembly linker. Table 3-3 details the four assembly formats.

Table 3-3. The Four Formats for an Assembly

Assembly Format

Description

exe

A console executable. The assembly must contain one entry point, which is defined as a valid Main method.

library

A type library that can be used by other assemblies.

module

A nonexecutable collection of compiled code for use in other assemblies.

 

See the Modules section later in this chapter for details.

winexe

A graphical Windows executable. The assembly must contain one entry point, which is defined as a valid Main method.

Contents of an Assembly

An assembly comprises the following elements:

  • An assembly manifest that contains metadata.

  • One or more modules.

  • Resource files, such as icons for Windows applications.

The Manifest

Every assembly contains a manifest consisting of metadata describing the assembly and the types contained within the assembly. The manifest contains the information described in Table 3-4.

Table 3-4. Information Defined in a Manifest

Information

Description

Name

The name of the assembly.

Version

A major and minor version number, and a revision and build number. The common language runtime uses these numbers to enforce version policy.

Culture

Information about the culture or language that the assembly supports, similar to the Internationalization and Localization concepts in Java. This is required only for assemblies that contain solely localized resources, such as culture-specific strings, known as "satellite" assemblies.

Strong name

Strong names are discussed in detail in Appendix B.

Assembly contents

A list of files that make up the assembly. See the Creating a Multifile Assembly section later in this chapter for more information.

Type information

Details of types exported by the assembly.

References

Details of assemblies required to support the types contained in the assembly.

General information

General details, such as the company that produced the assembly, a description string, and copyright information.

The first four items (name, version, culture, and strong name) are used to identify an assembly. Most of the information in the manifest is generated automatically when the assembly is created. The general information can be specified by the programmer. See the sections on single-file and multifile assemblies for more information.

Modules

As detailed in the following list, an appreciation of modules is important in understanding assemblies.

  • Modules contain one or more .NET types described in MSIL.

  • Modules can contain types from more than one namespace, and namespaces can span more than one module. Namespaces are discussed in Chapter 4.

  • Modules can be compiled from one or more source files.

  • Modules cannot be used directly by the common language runtime.

Modules are designed to ease the development process by allowing independent development of modules, which can be written in different .NET-supported languages. These modules are later combined into a single assembly. Modules are created with the C# compiler using the option /target:module, for example:

csc /target:module /out:MyModule.netmodule
    FirstSourceFile.cs SecondSourceFile.cs

The output of this command will be a file named MyModule.netmodule containing MSIL representations of the types defined in the source files; the .netmodule extension is the default for modules. The module file contains the following information:

  • A manifest listing the assemblies that the types in the module rely on and a declaration of the module name.

  • The types compiled from the source files, grouped by namespace.

Modules can rely on the types contained in other modules. This is achieved by using the /addmodule compiler switch. The following command demonstrates how to compile a source file that relies on types defined in MyModule.netmodule:

csc /addmodule:MyModule.netmodule /target:module SourceFile.cs

Using the /addmodule switch allows the compiler to load the types contained in the original module and to correctly compile the types contained in the source file.

Resources

As well as a manifest and modules, assemblies can contain resources. Resources enable text and images to be separated from the logic of the application, thereby easing the tasks of maintenance and localization of applications.

Single-File and Multifile Assemblies

Assemblies can comprise either a single file (a single-file assembly) or a set of files (a multifile assembly). A single-file assembly combines one module with metadata into a single disk file. The C# compiler creates single-file assemblies by default.

Multifile assemblies consist of one or more modules and a separate file containing the assembly manifest. Multifile manifests would be used for the following reasons:

  • To combine modules written in different languages. For example, the C# compiler, by default, creates a single-file assembly containing MSIL generated only from C# code. To include a module written in Microsoft Visual Basic .NET, or any other supported .NET programming language, in an assembly, a multifile assembly is used.

  • To minimize the consumption of system resources by including rarely used types in a separate module. The common language runtime will load modules as required.

  • To support the independent development of application components, which is commonly known as component programming.

The manifest file and the module files form a single unit and cannot be separated; these files must be deployed together. The manifest file does not directly incorporate any of the types included in the modules.

Creating a Single-File Assembly

The following statement compiles two source files into a single-file assembly:

csc /target:exe /out:Application.exe
    MyApplication.cs MySupportClass.cs

This command creates a new assembly named Application.exe using the exe format. Exe and winexe assembly formats must have an entry point, typically a Main method. If more than one component defines a Main method, the compiler relies on the /main switch to indicate which should be used. Unlike Java applications, .NET assemblies are not started by specifying a class; the identity of the application entry point is included in the assembly.

Setting metadata for a single-file assembly

For single-file assemblies, metadata can be defined in a C# source file. Microsoft Visual Studio .NET automatically creates a file named AssemblyInfo.cs, which contains placeholder definitions. If this source file is included in a compilation, the statements are used to construct the assembly manifest.

To demonstrate your ability to purposefully define the informational elements of the manifest, we’ll create a file named AssemblyInfo.cs, which contains the following statements:

using System.Reflection;
using System.Runtime.CompilerServices;

[assembly: AssemblyTitle("MyAssembly")]
[assembly: AssemblyDescription("This is a single-file assembly")]
[assembly: AssemblyCompany("MyCompany")]
[assembly: AssemblyProduct("MyProduct")]
[assembly: AssemblyCopyright("2002, My Company")]

This file contains statements that are interpreted by the C# compiler when creating an assembly. We define our programming logic in the MyApplication.cs file, as shown here:

class MyApplication  {
    static void Main(string[] args) {
        System.Console.WriteLine("Hello World!");
    }
}

To create a single-file assembly incorporating the manifest information and the code file, use the following command:

csc /target:exe /out:Application.exe MyApplication.cs AssemblyInfo.cs

The information supplied in the AssemblyInfo.cs file can be seen on the Version tab in the Windows Explorer properties window for the Application.exe file. Metadata is also available through runtime reflection. Figure 3-1 shows the metadata for the sample assembly viewed via the Windows Explorer "Version" tab.

Metadata for a single-file assembly

Figure 3-1. Metadata for a single-file assembly

More Info

For details of reflection, see Chapter 12.

Creating a Multifile Assembly

Multifile assemblies are created using the assembly linker (al.exe). The linker takes a number of modules and generates a file that contains the assembly manifest data. To demonstrate creating a multifile assembly, we’ll create two classes and compile each into a separate module. The first class is shown here and should be stored in a file named StringPrinter.cs:

public class StringPrinter {
    public void printString(string messageString) {
        System.Console.WriteLine("Message: " + messageString);
    }
}

This class contains a single method that accepts a string argument and prints a message to the console.

The second class should be stored in a file named HelloWorld.cs, shown here:

class HelloWorld {
    public static void Main(string[] args) {
        StringPrinter myPrinter = new StringPrinter();
        myPrinter.printString("Hello World!");
    }
}

The HelloWorld class contains a Main method that creates a new instance of the StringPrinter class and invokes the printString method with the string Hello World as an argument. We compile each class into a module using the following statements. Note that because the HelloWorld class relies on the String-Printer class, we need to add an /addmodule switch to ensure that the types can be resolved correctly:

csc /target:module StringPrinter.cs
csc /addmodule:StringPrinter.netmodule /target:module HelloWorld.cs

These statements create two modules, named HelloWorld.netmodule and StringPrinter.netmodule. We combine these into an assembly by using the assembly linker as in the following statement:

al /out:App.exe /target:exe /main:HelloWorld.Main
    HelloWorld.netmodule StringPrinter.netmodule

Here are the details:

  • The /out switch specifies the name of the manifest file.

  • The /target switch specifies the format for the assembly.

  • The /main switch specifies the application entry point, in this case the Main method contained in the HelloWorld class.

  • The remaining arguments are the file names of the modules that should be included in the assembly.

Executing the App.exe file results in "Message: Hello World!" being printed on the console. If any of the module files are missing, the CLR will report an error indicating that a dependency cannot be resolved.

Setting metadata for a multifile assembly

The statements used to set the assembly metadata for a single-file assembly are interpreted by the C# compiler. When using the assembly linker to create a multifile assembly, the metadata can be specified using command-line switches. The following command illustrates setting metadata via the command line; the switches that were used to set metadata appear in boldface:

al /out:App.exe /target:exe /main:HelloWorld.Main
    /title:MyAssembly
    /description:"This is a multifile assembly"
    /company:MyCompany
    /product:MyProduct
    HelloWorld.netmodule StringPrinter.netmodule
..................Content has been hidden....................

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