Microsoft Visual C#.NET 2003 Kick Start
Assemblies can contain several modules, and we're going to create a multi-module assembly next . An assembly includes a hash code for each module, which is a numeric representation of the module's code used for version verification. The Visual Studio IDE can't create multi-module assemblies for C#, although it can for C++, so we're going to use the command-line compiler, csc, in this example. This example shows how to link several modules into the same assembly. In this case, we're going to define a string-handling class, ch13_02, in one module, and use it in another. In ch13_02.cs, we'll define the ch13_02 class in a namespace called MultiModule and give that class a property named Text that will hold a string of text:
namespace MultiModule { class ch13_02 { string privateText; public string Text { get { return privateText; } set { privateText = value; } } . . . We'll also give this class a public method, LowerCase , which will convert the stored string to lowercase and return it, as you see in Listing 13.2. Listing 13.2 Defines the ch13_02 Class (ch13_02.cs)
using System; namespace MultiModule { public class ch13_02 { string privateText; public string Text { get { return privateText; } set { privateText = value; } } public string LowerCase() { return privateText.ToLower(); } } } We're going to use ch13_02 objects in a new module, ch13_03.cs. In this module, we'll use the MultiModule namespace and create a new object of the ch13_02 class named stringer :
using System; using MultiModule; class ch13_03 { public static void Main() { ch13_02 stringer = new ch13_02(); . . . Now we can assign the text "No Worries!" to the string object's Text property and convert that text to lowercase with the LowerCase method just before displaying it, as you see in Listing 13.3. Listing 13.3 Using the ch13_02 Class (ch13_03.cs)
using System; using MultiModule; class ch13_03 { public static void Main() { ch13_02 stringer = new ch13_02(); stringer.Text = "No Worries!"; Console.WriteLine(stringer.LowerCase()); } } We'll also include some manifest information for the assembly we're going to build in a third file, ch13_04.cs, which you can see in Listing 13.4. Listing 13.4 Defines the ch13_03 Assembly (ch13_04.cs)
using System.Reflection; [assembly: AssemblyTitle("Example ch13_02")] [assembly: AssemblyVersion("1.0.0.0")] To compile the first module, ch13_02.cs, use the /t:module switch like this:
C:\>csc /t:module ch13_02.cs This creates the file ch13_02.netmodule. The code in ch13_03.cs makes use of the ch13_02 class defined in ch13_02.netmodule, so we'll use the /addmodule switch to include the needed code from ch13_02 when we compile ch13_03:
C:\>csc /addmodule:ch13_02.netmodule /t:module ch13_03.cs This creates ch13_03.netmodule. All we need is the final module, created from ch13_04.cs, which holds the manifest information for this assembly:
C:\>csc /t:module ch13_04.cs This creates ch13_04.netmodule. To link these modules into one assembly, which we'll call ch13_03.exe (because Main is in ch13_03.cs), you use the assembly linker, al, which comes with Visual Studio, al.exe (where xxxxxxxxxx is the .NET version number). Here's how we create our assembly. Note the /main switch, which lets you specify the entry point for the assembly, the /out switch, which lets you name the output file, and the /t:exe switch, which specifies that the type of this assembly is an .EXE file:
C:\>al ch13_02.netmodule ch13_03.netmodule ch13_04.netmodule /main:ch13_03.Main /out:ch13_03.exe /t:exe This links our modules into the same assembly and creates ch13_03.exe. When you run ch13_03.exe, you see that the text is indeed converted to lowercase:
C:\>ch13_03 no worries! You can see the three modules we've put into this assembly in the assembly's manifest:
.module extern ch13_03.netmodule .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4.. .hash = (AB 74 A6 A8 1D E6 70 59 FD BE DE D7 9F 2F E3 E4 // .t....pY...../.. 7B 27 2C 18 ) // {',. .ver 1:0:5000:0 } .assembly ch13_03 { // --- The following custom attribute is added automatically, // do not uncomment ------- // .custom instance void // [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool, // bool) = ( 01 00 00 01 00 00 ) .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0F 45 78 61 6D 70 6C 65 20 63 68 31 33 5F // ...Example ch13_ 30 32 00 00 ) // 02.. .hash algorithm 0x00008004 .ver 1:0:0:0 } .file ch13_02.netmodule .hash = (18 D5 D4 B6 C8 44 12 C3 82 EB E4 24 75 F1 2D 5C // .....D.....$u.-\ 4C 4D 8A 49 ) // LM.I .file ch13_03.netmodule .hash = (1A 36 CC F6 E8 B6 5D 5A D9 65 2C 9F 8C 9D D8 F5 // .6....]Z.e,..... 1C A3 BC AB ) .file ch13_04.netmodule .hash = (24 D5 92 AC AB 32 33 7C 3B CA D6 18 1B 0B 01 BD // $....23;....... E6 5A 10 C4 ) // .Z.. .module ch13_03.exe // MVID: {9B78128A-5400-4CA1-ADA6-C24F67494F1C} .imagebase 0x00400000 .subsystem 0x00000003 .file alignment 512 .corflags 0x00000001 // Image base: 0x07090000 It's also worth noting that you can load any kind of file into an assembly using the /embed switch. For example, here's how you can include a .JPG file in an assembly.
C:\>al ch13_02.netmodule ch13_03.netmodule ch13_04.netmodule /embed:ch13_03.jpg /main:ch13_03.Main /out:ch13_03.exe /t:exe You can build a DLL instead of an EXE using the /out and /t:library switches like this, which converts ch13_02.cs into ch13_02.dll:
C:\>csc /out:ch13_02.dll /t:library ch13_02.cs Microsoft (R) Visual C# .NET Compiler version xxxxxxxxxx for Microsoft (R) .NET Framework version xxxxxxxxxx Copyright (C) Microsoft Corporation 2001-2002. All rights reserved. You can then add a reference to the ch13_02.dll DLL (instead of the earlier module ch13_02.netmodule) when you compile the file that uses it, ch13_03.cs:
C:\>csc /r:ch13_02.dll /t:module ch13_03.cs Microsoft (R) Visual C# .NET Compiler version xxxxxxxxxx for Microsoft (R) .NET Framework version xxxxxxxxxx Copyright (C) Microsoft Corporation 2001-2002. All rights reserved. Now you can link ch13_03.netmodule and ch13_04.netmodule into ch13_03.exe:
C:\>al ch13_03.netmodule ch13_04.netmodule /main:ch13_03.Main /out:ch13_03.exe /t:exe Microsoft (R) Assembly Linker version xxxxxxxxxx for Microsoft (R) .NET Framework version xxxxxxxxxx Copyright (C) Microsoft Corporation 2001-2002. All rights reserved. And that creates ch13_03.exe as before, except that this time, we created and used a DLL. You can make also make use of DLLs like ch13_02.dll in the IDE, and that's coming up next. |