1. C# Compiler - CSC.exe
csc.exe /out:Program.exe /t:exe /r:MSCorLib.dll Program.cs
This command line tells the C# compiler to emit an executable file called Program.exe ( /out:Program.exe). The type of file produced is a Win32 console application ( /t[arget]:exe).
csc.exe /out:Program.exe /t:exe Program.cs
The C# compiler automatically references the MSCorLib.dll assembly.
csc.exe Program.cs
Furthermore, the /out:Program.exe and the /t:exe command-line switches also match what the C# compiler would choose as defaults.
/nostdlib switch
The C# compiler doesn't reference the MSCorLib.dll assembly.
Windows supports two types of applications, those with a console user interface ( CUI) and those with a graphical user interface ( GUI). Because I specified the /t:exe switch, the C# compiler produced a CUI application. You’d use the /t:winexe switch to cause the C# compiler to produce a GUI application.
/t:exe
/t:winexe
/t:library
The C# compiler produces an assembly when you specify any of the following command-line switches: /t[arget]:exe, /t[arget]:winexe, or /t[arget]:library. All of these switches
cause the compiler to generate a single PE file that contains the manifest metadata tables. The resulting file is either a CUI executable, a GUI executable, or a DLL, respectively.
/t:module
This switch tells the compiler to produce a PE file that doesn’t contain the manifest metadata tables. The PE file produced is always a DLL PE file, and this file must be added to an assembly before the CLR can access any types within it. When you use the /t:module switch, the C# compiler, by default, names the output file with an extension of .netmodule.
e.g csc /t:module RUT.cs
This will produce a standard DLL PE file named RUT.netmodule. But, the CLR can't load it.
/addmodule
This switch is used to add a module to an assembly.
e.g csc /out:JeffTypes.dll /t:library /addmodule:RUT.netmodule FUT.cs
This line tells the C# compiler to compile the FUT.cs file to produce the JeffTypes.dll file. Because /t:library is specified, a DLL PE file containing the manifest metadata tables is emitted into the JeffTypes.dll file. The /addmodule:RUT.netmodule switch tells the compiler that RUT.netmodule is a file that should be considered part of the assembly. Specifically, the /addmodule switch tells the compiler to add the file to the FileDef manifest metadata table and to add RUT.netmodule’s publicly exported types to the ExportedTypesDef manifest metadata table.
Any client code that consumes the JeffTypes.dll assembly’s types must be built using the /r[eference]:JeffTypes.dll compiler switch. This switch tells the compiler to load the JeffTypes.dll assembly and all of the files listed in its FileDef table when searching for an external type. The compiler requires all of the assembly’s files to be installed and accessible.
/resource
The C# compiler’s /resource switch embeds the specified resource file into the resulting assembly PE file, updating the ManifestResourceDef table.
/linkresource
The compiler’s /linkresource switch adds an entry to the ManifestResourceDef and the FileDef manifest tables to refer to a stand-alone resource file.
2. MSCorLib.dll
MSCorLib.dll is a special file in that it contains all the core types: Byte, Char, String, Int32, and many more. In fact, these types are so frequently used that the C# compiler automatically references the MSCorLib.dll assembly.
3. Respone File
A response file is a text file that contains a set of compiler commandline switches. When you execute CSC.exe, the compiler opens response files and uses any switches that are specified in them as though the switches were passed to CSC.exe on the command line. You instruct the compiler to use a response file by specifying its name on the command line prepended by an @ sign.
For example: you could have a response file called MyProject.rsp that contains the following text:
/out:MyProject.exe
/target:winexe
To cause CSC.exe to use these settings, you’d invoke it as follows:
csc.exe @MyProject.rsp CodeFile1.cs CodeFile2.cs
The C# compiler supports multiple response files. In addition to the files you explicitly specify on the command line, the compiler automatically looks for files called CSC.rsp. When you
run CSC.exe, it looks in the current directory for a local CSC.rsp file—you should place any project-specific settings in this file. The compiler also looks in the directory containing the CSC.exe file for a global CSC.rsp file. Settings that you want applied to all of your projects should go in this file. The compiler aggregates and uses the settings in all of these response files. If you have conflicting settings in the local and global response files, the settings in the local file override the settings in the global file. Likewise, any settings explicitly passed on the command line override the settings taken from a local response file.
When you install the .NET Framework, it installs a default global CSC.rsp file in the %SystemRoot%\Microsoft.NET\Framework\vX.X.Xdirectory (where X.X.X is the version of the .NET Framework you have installed).
You can tell the compiler to ignore both local and global CSC.rsp files by specifying the /noconfig command-line switch.
4. Metadata
A managed PE file has four main parts: the PE32(+) header, the CLR header, the metadata, and the IL.
The PE32(+) header is the standard information that Windows expects.
The CLR header is a small block of information that is specific to modules that require the CLR (managed modules). The header includes the major and minor version number of the CLR that the module was built for: some flags, a MethodDef token indicating the module’s entry point method if this module is a CUI or GUI executable, and an optional strong-name digital signature. Finally, the header contains the size and offsets of certain metadata tables contained within the module. You can see the exact format of the CLR header by examining the IMAGE_COR20_HEADER defined in the CorHdr.h header file.
The metadata is a block of binary data that consists of several tables. There are three categories of tables: definition tables, reference tables, and manifest tables.
Method Flag [HideBySig] hidebysig is supplied for the use of tools and is ignored by the VES. It specifies that the declared method hides all methods of the base class types that have a matching method signature; when omitted, the method should hide all methods of the same name, regardless of the signature.
上面的英文摘自ECMA关于CLI的标准。用hidebysig修饰的方法会隐藏掉基类中具有相同签名的方法,这么看来相当于在方法前加上了new关键字
Method Flag [ReuseSlot] Indicates that the method will reuse an existing slot in the vtable. This is the default behavior.
Method Flag [NewSlot] Indicates that the method always gets a new slot in the vtable.
For the curious, metadata tokens are 4-byte values. The high byte indicates the type of token (0x01=TypeRef, 0x02=TypeDef, 0x23=AssemblyRef, 0x26=FileRef, 0x27=ExportedType). For the complete list, see the CorTokenType enumerated type in the CorHdr.h file included with the .NET Framework SDK. The three lower bytes of the token simply identify the row in the corresponding metadata table. For example, the implementation token 0x26000001 refers to the first row of the FileRef table. For most tables, rows are numbered starting with 1, not 0. For the TypeDef table, rows actually start with 2.
typedef enum CorTokenType
{mdtModule = 0x00000000, //mdtTypeRef = 0x01000000, //mdtTypeDef = 0x02000000, //mdtFieldDef = 0x04000000, //mdtMethodDef = 0x06000000, //mdtParamDef = 0x08000000, //mdtInterfaceImpl = 0x09000000, //mdtMemberRef = 0x0a000000, //mdtCustomAttribute = 0x0c000000, //mdtPermission = 0x0e000000, //mdtSignature = 0x11000000, //mdtEvent = 0x14000000, //mdtProperty = 0x17000000, //mdtModuleRef = 0x1a000000, //mdtTypeSpec = 0x1b000000, //mdtAssembly = 0x20000000, //mdtAssemblyRef = 0x23000000, //mdtFile = 0x26000000, //mdtExportedType = 0x27000000, //mdtManifestResource = 0x28000000, //mdtGenericParam = 0x2a000000, //mdtMethodSpec = 0x2b000000, //mdtGenericParamConstraint = 0x2c000000,mdtString = 0x70000000, //mdtName = 0x71000000, //mdtBaseType = 0x72000000, // Leave this on the high end value. This does not correspond to metadata table} CorTokenType;
5. Assembly Linker - AL.exe
The Assembly Linker is useful if you want to create an assembly consisting of modules built from different compilers (if your compiler doesn’t support the equivalent of C#’s /addmodule switch) or perhaps if you just don’t know your assembly packaging requirements at build time.
The AL.exe utility can produce an EXE or a DLL PE file that contains only a manifest describing the types in other modules. The
Assembly Linker has no way to combine multiple files into a single file.
e.gcsc /t:module RUT.cscsc /t:module FUT.csal /out:JeffTypes.dll /t:library FUT.netmodule RUT.netmodule
The AL.exe utility can also produce CUI and GUI PE files by using the /t[arget]:exe or /t[arget]:winexe command-line switches. But this is very unusual since it would mean that you’d have an EXE PE file with just enough IL code in it to call a method in another module. You can specify which method in a module should be used as an entry point by adding the /main command-line switch when invoking AL.exe. The following is an example of how to call the Assembly Linker, AL.exe, by using the /main command-line switch:
e.gcsc /t:module /r:JeffTypes.dll Program.csal /out:Program.exe /t:exe /main:Program.Main Program.netmodule
When using AL.exe to create an assembly, you can add a file as a resource to the assembly by using the /embed[resource] switch. This switch takes a file (any file) and embeds the file’s
contents into the resulting PE file. The manifest’s ManifestResourceDef table is updated to reflect the existence of the resources.
AL.exe also supports a /link[resource] switch, which also takes a file containing resources. However, the /link[resource] switch updates the manifest’s ManifestResourceDef and FileDef tables, indicating that the resource exists and identifying which of the assembly’s files contains it. The resource file is not embedded into the assembly PE file; it remains separate and must be packaged and deployed with the other assembly files.
/c[ulture]:<text>
This switch will add culture infromation.
Like AL.exe, CSC.exe also allows you to combine resources into an assembly produced by the C# compiler. The C# compiler’s /resource switch embeds the specified resource file into the resulting assembly PE file, updating the ManifestResourceDef table. The compiler’s /linkresource switch adds an entry to the ManifestResourceDef and the FileDef manifest tables to refer to a stand-alone resource file.
6. Satellite assembly
Resource-Only Assembly
Assemblies that are marked with a culture are called satellite assemblies.
You’ll usually use the AL.exe tool to build a satellite assembly. You won’t use a compiler because the satellite assembly should have no code contained within it. When using AL.exe, you specify the desired culture by using the /c[ulture]:text switch, where text is a string such as “ en-US,” representing U.S. English. When you deploy a satellite assembly, you should place it in a subdirectory whose name matches the culture text. For example, if the application’s base directory is C:\MyApp, the U.S. English satellite assembly should be placed in the C:\MyApp\en-US subdirectory. At runtime, you access a satellite assembly’s resources by using the System.Resources.ResourceManager class.
Note: It is possible to create a satellite assembly that contains code, though this practice is discouraged. If you prefer, you can specify the culture by using the System.Reflection.AssemblyCultureAttribute custom attribute instead of using AL.exe’s /culture switch, for example, as shown here:
e.g
// Set assembly's culture to Swiss German[assembly:AssemblyCulture("de-CH")]
7. Assembly Version Resources
e.g
using System.Reflection;
// FileDescription version information:[assembly: AssemblyTitle("JeffTypes.dll")]// Comments version information:[assembly: AssemblyDescription("This assembly contains Jeff's types")]// CompanyName version information:[assembly: AssemblyCompany("Wintellect")]// ProductName version information:[assembly: AssemblyProduct("Wintellect (R) Jeff's Type Library")]// LegalCopyright version information:[assembly: AssemblyCopyright("Copyright (c) Wintellect 2010")]// LegalTrademarks version information:[assembly:AssemblyTrademark("JeffTypes is a registered trademark of Wintellect")]// AssemblyVersion version information:[assembly: AssemblyVersion("3.0.0.0")]// FILEVERSION/FileVersion version information:[assembly: AssemblyFileVersion("1.0.0.0")]// PRODUCTVERSION/ProductVersion version information:[assembly: AssemblyInformationalVersion("2.0.0.0")]// Set the Language field (discussed later in the "Culture" section)[assembly:AssemblyCulture("")]
You can use AL.exe's command-line switches to set this information instead of using the custom attributes.
Version Resource AL.exe Switch Custom Attribute/Comment
FILEVERSION /fileversion System.Reflection.AssemblyFileVersionAttribute.PRODUCTVERSION /productversion System.Reflection.AssemblyInformationalVersionAttribute.FILEFLAGSMASK (none) Always set to VS_FFI_FILEFLAGSMASK (defined in WinVer.h as 0x0000003F).FILEFLAGS (none) Always 0.FILEOS (none) Currently always VOS__WINDOWS32.FILETYPE /target Set to VFT_APP if /target:exe or /target:winexe is specified; set to VFT_DLL if /target:library is specified.FILESUBTYPE (none) Always set to VFT2_UNKNOWN. (This field has no meaning for VFT_APP and VFT_DLL.)AssemblyVersion /version System.Reflection.AssemblyVersionAttribute.Comments /description System.Reflection.AssemblyDescriptionAttribute.CompanyName /company System.Reflection.AssemblyCompanyAttribute.FileDescription /title System.Reflection.AssemblyTitleAttribute.FileVersion /version System.Reflection.AssemblyFileVersionAttribute.InternalName /out Set to the name of the output file specified (without the extension).LegalCopyright /copyright System.Reflection.AssemblyCopyrightAttribute.LegalTrademarks /trademark System.Reflection.AssemblyTrademarkAttribute.OriginalFilename /out Set to the name of the output file (without a path).PrivateBuild (none) Always blank.ProductName /product System.Reflection.AssemblyProductAttribute.ProductVersion /productversion System.Reflection.AssemblyInformationalVersionAttribute.SpecialBuild (none) Always blank.
8. Version Numbers
Version numbers have the format: each consists of four period-separated parts.
The first two numbers make up the public perception of the version. The public will think of this example as version 2.5 of the assembly. The third number, 719, indicates the build of the assembly. If your company builds its assembly every day, you should increment the build number each day as well. The last number, 2, indicates the revision of the build. If for some reason your company has to build an assembly twice in one day, maybe to resolve a hot bug that is halting other work, the revision number should be incremented.
9. Culture
Like version numbers, assemblies also have a culture as part of their identity.
e.g
In general, if you create an assembly that contains code, you don’t assign a culture to it. This is because code doesn’t usually have any culture-specific assumptions built into it. An assembly that isn’t assigned a culture is referred to as being culture neutral.
10. Simple Application Deployment
Assemblies deployed to the same directory as the application are called privately deployed assemblies because the assembly files aren’t shared with any other application (unless the other application is also deployed to the same directory). Privately deployed assemblies are a big win for developers, end users, and administrators because they can simply be copied to an application’s base directory, and the CLR will load them and execute the code in them. In addition, an application can be uninstalled by simply deleting the assemblies in its directory. This allows simple backup and restore as well.
This simple install/move/uninstall scenario is possible because each assembly has metadata indicating which referenced assembly should be loaded; no registry settings are required. In addition, the referencing assembly scopes every type. This means that an application always binds to the same type it was built and tested with; the CLR can’t load a different assembly that just happens to provide a type with the same name. This is different from COM, in which types are recorded in the registry, making them available to any application running on the machine.
11. Simple Administrative Control (Configuration)
To allow administrative control over an application, a configuration file can be placed in the application’s directory.
e.g
<configuration><runtime><assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"><probing privatePath="AuxFiles" /></assemblyBinding></runtime></configuration>
The name and location of this XML configuration file is different depending on the application type:
For executable applications (EXEs), the configuration file must be in the application’s base directory, and it must be the name of the EXE file with “ .config” appended to it.
For Microsoft ASP.NET Web Form applications, the file must be in the Web application’s virtual root directory and is always named Web.config. In addition, subdirectories can also contain their own Web.config file, and the configuration settings are inherited. For example, a Web application located at http://Wintellect.com/Training would use the settings in the Web.config files contained in the virtual root directory and in its Training subdirectory.
Configuration settings apply to a particular application and to the machine. When you install the .NET Framework, it creates a Machine.config file. There is one Machine.config file per version of the CLR you have installed on the machine.
The Machine.config file is located in the following directory:
%SystemRoot%\Microsoft.NET\Framework\version\CONFIG
Of course, %SystemRoot% identifies your Windows directory (usually C:\WINDOWS), and version is a version number identifying a specific version of the .NET Framework (something like v4.0.#####).