cuclife.com > IT > C# > 0

CLR via C# 2.2 将类型生成为模块

网络整理 - 06-27

2.1节主要介绍.NET Framework的部署目标。作者首先提出Windows系统复杂且不稳定,接着分析原因(DLL hell、安装的复杂性和安全问题)。而.NET Framework很大程度上解决了DLL hell,安装也简化了,并且包含了代码访问安全(code access security)这样一个安全模型。

在2.2节中,主要介绍如何将一个包含不同类型的源文件,转换为可部署的文件。以下面这个简单的程序为例:

public sealed class Program { public static void Main() { System.); } }

该程序定义了一个类型,Program。该类型有一个公有的、静态的方法,Main。在Main方法中包含对其他类型System.Console的引用。System.Console是微软实现的类型,实现该类型中方法的IL代码位于MSCorLib.dll文件中。因此,我们的程序定义了一个类型,并且使用了其他公司的类型。

要生成这个示例应用,先将代码放到一个源代码文件中(Program.cs),然后执行下面的命令行:

csc.exe /out:Program.exe /t:exe /r:MSCorLib.dll Program.cs

这个命令行告诉我们,C#编译器生成了一个名为Program.exe的可执行文件(/out:Program.exe)。生成的文件类型为Win32控制台程序(/t[arget]:exe)。

当C#编译器处理源文件时,它会发现代码引用了System.Console类型的WriteLine方法。这时,编译器需要确保该类型存在,并且包含WriteLine方法,并且传递的参数与期望的相匹配。由于该类型不是C#源代码内定义的,为了取悦C#编译器,你必须提供一组程序集来处理引用的外部类型。在上面的命令行中,使用了/r[eference]:MSCorLib.dll选项,告诉编译器到MSCorLib.dll文件中查找外部类型。

MSCorLib.dll包含了所有的核心类型:Byte、Char、String、Int32等。由于这些类型使用频繁,因此C#编译器自动引用MSCorLib.dll程序集。换句话说,下面的命令行(省略了/r选项)与上面的结果相同:

csc.exe /out:Program.exe /t:exe Program.cs

此外,由于/out:Program.exe和/t:exe命令行选项也是C#编译器默认的,因此下面和上面的结果相同:

csc.exe Program.cs

如果由于某种原因不希望C#编译器引用MSCorLib.dll程序集,可以使用/nostdlib选项。微软使用该选项生成MSCorLib.dll程序集本身。例如,在编译Program.cs文件时使用下面的命令行会报错,因为System.Console类型定义在MSCorLib.dll中:

csc.exe /out:Program.exe /t:exe /nostdlib Program.cs

对于初学者来说,Program.exe是一个标准的可移植可执行(PE)文件。这意味着运行32位或64位版本Windows的机器可以加载该文件并执行。Windows支持两种类型的应用程序:控制台用户界面(CUI)程序和图形用户界面程序(GUI)。/t:exe选项对应CUI程序,/t:winexe选项对应GUI程序。

响应文件(Response File)

响应文件是包含一组编译器选项的文本文件。当执行CSC.exe时,编译器打开响应文件,使用其中的编译器选项进行编译。要想让编译器使用响应文件,需要在命令行中使用@asign指定其名称。例如,响应文件MyProject.rsp包含如下文本:

/out:MyProject.exe /target:winexe

要让CSC.exe使用这些设置,需要像下面这样调用:

csc.exe @MyProject.rsp CodeFile1.cs CodeFile2.cs

这通知C#编译器输出文件的名称和创建的目标类型。响应文件十分方便,因为你不必每次都手动传递所需的命令行参数。

C#编译器支持多个响应文件。除了你在命令行中明确指定的文件,编译器还自动查找名为CSC.rsp的文件。运行CSC.exe时,会在当前目录查找本地CSC.rsp文件——你需要在该文件中放置project-specific的设置。编译器还会在CSC.exe文件所在的目录中查找全局CSC.rsp文件。对所有项目进行的设置可以放置这个文件中。编译器会组合并使用所有响应文件中的设置。如果本地和全局响应文件之间的设置有冲突,本地文件中的设置优于全局文件中的设置。同样地,任何显式传递给命令行的设置都优于本地响应文件中的设置。

在安装.NET Framework时,会将默认的全局CSC.rsp文件安装在%SystemRoot%\Microsoft.NET\Framework\vX.X.X目录下。4.0版本的文件包含如下设置:

# This file contains command-line options that the C# # command line compiler (CSC) will process as part # of every compilation, unless the "/noconfig" option # is specified. # Reference the common Framework libraries /r:Accessibility.dll /r:Microsoft.CSharp.dll /r:System.Configuration.dll /r:System.Configuration.Install.dll /r:System.Core.dll /r:System.Data.dll /r:System.Data.DataSetExtensions.dll /r:System.Data.Linq.dll /r:System.Deployment.dll /r:System.Device.dll /r:System.DirectoryServices.dll /r:System.dll /r:System.Drawing.dll /r:System.EnterpriseServices.dll /r:System.Management.dll /r:System.Messaging.dll /r:System.Numerics.dll /r:System.Runtime.Remoting.dll /r:System.Runtime.Serialization.dll /r:System.Runtime.Serialization.Formatters.Soap.dll /r:System.Security.dll /r:System.ServiceModel.dll /r:System.ServiceProcess.dll /r:System.Transactions.dll /r:System.Web.Services.dll /r:System.Windows.Forms.Dll /r:System.Xml.dll /r:System.Xml.Linq.dll

由于全局CSC.rsp文件引用了上面所有的程序集,因此你不必显式使用/reference选项引用这些程序集。

引用所有这些程序集会使编译器变慢些许。但是,如果你的源代码没用引用任何这些程序集中定义的类型或成员,就不会对最终的程序集文件以及运行时的执行性能产生任何影响。

在使用/reference时,需要指定文件的完整路径。否则编译器会按照以下的顺序查找该文件:

  • 工作目录(working derectory)。
  • CSC.exe文件所在目录。MSCorLib.dll也在该目录中。通常为%SystemRoot%\Microsoft.NET\Framework\v4.0.#####这种形式。
  • 使用/lib选项指定的目录。
  • LIB环境变量指定的目录。
  • 当然,在全局CSC.rsp文件中添加自己的选项时没问题的。但是在不同的机器上复制编译环境就变得复杂了,需要更新每台机器的CSC.rsp文件。使用/noconfig命令行选项可以使编译器忽略本地和全局CSC.rsp文件。

    CLR via C# 2.2 将类型生成为模块