Building,Packaging,Deploying,and Administering Applications and Types

在咱们进入章节以前,咱们讨论一下生成、打包和部署你的应用程序和应用程序类型必须的步骤。在这章里,我关注的是如何为你的应用程序的用途生成程序集。在第三章,“共享程序集合和强命名程序集”,我会涉及你须要了解的高级概念,包括如何生成和使用包含类型的程序集,这些程序集将被多个应用程序共享。在这两章中,我也会讨论管理员能够影响执行应用程序和它的类型的方式。编程

现在,应用程序由几个类型组成,一般由你和微软建立。此外,有不少组件供应商建立和出售类型,其它公司购买能够减小软件项目开发时间。假如这些类型是用以CLR为目标的语言开发的,那么它们能够所有一块儿无缝的工做;一种语言写的一个类型可使用另外一个类型作为它基类而且不关心基础类型是用什么语言开发的。缓存

在这一章中,我将解释这些类型为了部署怎么生成和打包到文件。在这个过程当中,我将带你回顾一些.NET Framework解决的问题。安全

.NET Framework Depoyment Goals(.NET Framework部署目标)app

多年以来,Windows获得了一个不稳定和繁复的名声。这个名声是否名副其实要看不少不一样的因素。首先,全部的应用程序使用微软或其余供应商的动态连接库(DLLs)。由于一个应用程序从各类各样的供应商执行代码,开发者的任何一段代码都不能100%的肯定别人是怎么使用它的。即便这种类型的交互存在各类各样潜在的麻烦,事实上,这些问题通常不会出现由于应用程序在部署前都会进行测试和调试。less

不管如何,当一家公司决定更新它的代码和装载新的文件时用户运行常常会遇到问题。这些新文件被假设能向后兼容以前的文件,可是谁能够肯定?事实上,当一家供运商更新它的代码时,它通常发现它不可能从新测试和调试全部已装载的应用程序以确保有不但愿的影响。ide

我相信每一个读这本书的人都经历过这个问题的衍生:当安装一个新的应用程序,你发现它以某种方式破坏了一个已经安装好的应用程序。这种困境是众所周知的“DLL地狱”。这种类型不稳定在通常的电脑使用者内心和大脑中都留下了恐惧的烙印。结果是用户不得不当心考虑是否在他们的机器上安装一个新的软件。就我本身来讲,我决定不尝试安装应用程序走出恐惧,它可能会对我依赖的应用程序产生不利的影响。工具

第二个缘由,给前面说起的Windows名声作出贡献的是安装的复杂性。现在,当安装了大多数应用程序,它们影响系统全部的部分。例如,安装一个应用程序引发文件被拷贝到不一样目录,更新注册表,在你的桌面和开始菜单/桌面安装快捷方式。这带来的问题是应用程序没有分离为一个单独的实体。你不能容易的备份应用程序由于你必须拷贝应用程序的文件和注册的相关部分。此外,你不能容易的从一个机器移动应用程序到另外一个机器。你必须在运行一次安装程序,全部文件和注册表才能设置正确。最终,你不能容易的卸载或者移除应用程序而没有这种讨厌的感受,应用程序的一些部分还潜伏在你的机器上。性能

第三个缘由和安全有关。当应用程序安装好了,伴随着它们的是各类各样的文件,其中不少是经过不一样的公司写的。此外,网页应用程序常常有代码(就像ActiveX控件)这样下载,用户甚至没有察觉代码已经安装在他们的机器上了。现在,这份代码能够执行任何操做,包括删除文件或发邮件。用户惧怕安装新的应用程序是正确的,由于它们会引发潜在的损害。为使用户舒服,系统中必须创建安全,用户能够明确地容许或者不容许不一样的公司开发的代码访问他们的系统资源。测试

.NET Framework把DLL地狱问题放在重要位置,就像你将在这章和第三章里看到的。.NET Framework在修复应用程序状态分散在用户硬盘的各个角落问题走了很远。例如,不像COM,类型不须要在在注册表中设置。不幸的是,应用程序依然须要快捷方式连接。至于安全,.NET Framework包含一个叫作代码访问安全(code access security)的安全模型。鉴于Windows安全是以用户身份为基础的,代码访问安全容许机主设置权限,从而控制下载的组件能够作什么。一个主机应用程序像Microsoft SQL Server只给代码少许受权,然而一个本地安装(自我寄宿)的应用程序运行时拥有全部权限。正如你将看到的,.NET Framework使用户能够控制安装什么和运行什么,总之,对于控制机器,Windows从未作的这么好。ui

Building Types into a Module(类型生成一个模块)

在这个场景,我将给你看怎么把你源文件(包含不一样的类型)转换成一个能够部署的文件。让咱们从仔细查看下面的简单应用程序开始。

public sealed class Program
    {
        public static void Main(string[] args)
        {
            System.Console.WriteLine("Hi");
        }
    }

这个应用程序定义了一个类型,叫作Program。这个类型有一个单独的公共的、静态的叫作Main的方法。在Main中应用了一个由微软实现的叫作System.Console.System.Console的类型,而且在MSCorLib.dll文件中实现了这个类型的方法的中间语言(IL)代码。因此咱们的应用程序定义了一个类型同时也使用了另外一个公司的类型。

生成这个简单的应用程序,把以前的代码放到一个源代码文件中,叫作,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]:MSCoreLib.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程序集时微软使用这个开关。例如,当CSC.exe尝试编译Program.cs文件时如下的命令行将会产生一个错误由于System.Console类型定义在MSCorLib.dll中。

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

如今,让咱们近一点看C#编译器生成的Program.exe文件。这个文件其实是什么?好吧,首先,它是一个标准的可移植执行体(portable executable,PE)文件。这意味着一个运行32位或者64位版本Windows的机器能够加载这个文件并用它作点什么。Windows支持三种类型的应用程序。创建一个控制台用户界面(console user interface,CUI)应用程序,指定/t:exe开关;创建一个图形用户界面(graphical user interface,GUI)应用程序,指定/t:winexe开关;创建一个Windows商店App,指定/t:appcontainerexe开关。

Response Files(响应文档)

在搁置关于编译的开关的讨论前,我要花一点时间谈谈响应文档。一个响应文件是一个包含一个编译器命令行开关集合的文本文件。当你执行CSC.exe,编译器打开响应文档并使用详细定义的开关就像命令行传递给CSC.exe的同样。你命令编译器经过在命令行前加@符号指定响应文件的名字使用指定的响应文件。例如,你有一个叫作MyProject.rsp的响应文件包含如下文本。

/out:MyProject.exe

/target:winexe

为了CSC.exe使用这些设置,你可使用如下内容调用。

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

这告诉C#编译器输出文件时什么名字和要建立什么目标类型。就你看见的,响应文档很方便由于你不须要每次编译你的项目时手动给命令行参数表达你的意愿。

C#编译器支持多个响应文档。除了文档外你显式指定在命令行的,编译器自动在CSC.rsp文档中查找。当你运行CSC.exe,它查找包含CSC.exe文件的目录以获得全局CSC.rsp文件。你须要应用到你的项目的设置应该都放在这个文件中了。编译器集合和使用在这些响应文档中的设置。假如你在本地和全局响应文档中有冲突设置,本地的设置重载在全局响应文件中的设置。一样的,任何在命令行显式传递的设置从本地响应文件重载设置。

当你安装.NET Framework,它在%SystemRoot%\Microsoft.NET\Framework(64)\vX.X.X (X.X.X是你安装的.NET Framework的版本)目录默认安装了全局CSC.rsp文件。最近的版本文件包含如下开关。

# 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.Data.OracleClient.dll
/r:System.Deployment.dll
/r:System.Design.dll
/r:System.DirectoryServices.dll
/r:System.dll
/r:System.Drawing.Design.dll
/r:System.Drawing.dll
/r:System.EnterpriseServices.dll
/r:System.Management.dll
/r:System.Messaging.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.ServiceModel.Web.dll
/r:System.ServiceProcess.dll
/r:System.Transactions.dll
/r:System.Web.dll
/r:System.Web.Extensions.Design.dll
/r:System.Web.Extensions.dll
/r:System.Web.Mobile.dll
/r:System.Web.RegularExpressions.dll
/r:System.Web.Services.dll
/r:System.Windows.Forms.Dll
/r:System.Workflow.Activities.dll
/r:System.Workflow.ComponentModel.dll
/r:System.Workflow.Runtime.dll
/r:System.Xml.dll
/r:System.Xml.Linq.dll

由于全局CSC.rsp文件引用了全部列出的程序集,你不须要经过C#编译器的/reference开关显式的引用这些程序集。这个响应文件给开发者提供了很大的便利由于它容许开发者使用定义在各类微软发布程序集中的类型和命名空间而不须要每次编译时指定一个/reference编译器开关。

引用全部程序集编译器会慢一点。可是若是你的源代码没有引用定义在这些程序集中的类型和成员,对于生成程序集文件没有任何影响,也不会影响运行时的执行性能。

注意 当你使用/reference编译器开关引用一个程序集时,你能够给特殊的文件指定一个完整的路径。可是,假如你没有指定路径,编译器会在如下列出的地方搜索文件(按列出的顺序):
*工做目录。
*包含CSC.exe文件的目录。MSCorLib.dll就是从这个目录中得到的。路径看起来有点像这个:%SystemRoot%\Microsoft.Net\Framework\v4.0.#####。
*使用/lib编译器开关指定的任何名录。
*使用LIB环境变量指定的任何目录。

固然,欢迎你在全局CSC.rsp文件中添加你本身的开关是你的生活更简单,可是这么作,当复制生成环境到不一样的机器时会变的更困难——你不得不记住在每一个生成机器上以相同的方式更新CSC.rsp。另外,你能够告诉编译器忽略本地和全局CSC.rsp文件经过指定/noconfig命令行开关。

A Brief Look at Metadata(简单查看元数据)

如今咱们知道咱们建立了什么类型的PE文件。可是实际在Program.exe文件中是什么?一个托管的PE文件有4个主要的部分:PE32(+)头,CLR头,元数据和IL。PE32(+)是Windows指望的标准信息。CLR头是一小块信息指定模块须要CLR(托管模块)。头文件里包括CLR的主要和次要版本号,模块须要构建的:一些标记,一个MethodDef口令(之后会描述)指出模块的入口点假如模块是一个CUI,GUI,或者Windows Store可执行文件,和一个可选的强名称的数字信号(在第三章讨论)。最后,头文件包含构成模块的特定元数据表的大小和偏移量。你能够经过检测定义在CorHdr.h头文件中的IMAGE_COR20_HEADER查看CLR的确切格式。

元数据是由几个表组成的一个二进制块。表有三个分类:定义表,引用表,和载货单表。下表描述了一些在模块的元数据块中较为常见的定义表。

Common Definition Metadata Tables(常见定义元数据表)

Metadata Definition Table Name(元数据定义表名称) Description(描述)
ModuleDef(模块定义) 是一个识别模块的条目。条目包括模块的文件名和扩展(无路径)和一个模块的版本ID(编译器在表单中建立的一个GUID)。这容许文件重命名当使用起始名称持续记录的时候。然而,很是不鼓励重命名文件,它可能会阻止CLR在运行时定位程序集,因此不要那么作。
TypeDef(类型定义) 每一个定义在模块中的类型的条目。每一个条目包括类型的名称,基础类型,和标记(public,private,等等)和它在MethodDef表中的全部方、在FieldDef表中的全部字段、在PropertyDef表中的全部属性、在EventDef表中的全部事件的索引。
MethodDef(方法定义) 每一个定义在模块中的方法的条目。每一个条目包括方法的名字,标记(private,public,virtual,abstract,static,final等等),签名,模块内的偏移量,在那能够找到它的IL代码。每一个条目也能够参考ParamDef表条目,在那能够找到更多关于方法参数的信息。
FieldDef(字段定义) 每一个定义在模块中的字段的条目。每一个条目包括标记(private,public,等等),类型和名称。
ParamDef(参数定义) 每一个定义在模块中的参数的条目。每一个条目包括标记(in,out ,retval,等等),类型和名称。
PropertyDef(属性定义) 每一个定义在模块中的属性的条目。每一个条目包括标记,类型和名称。
EventDef(事件定义) 每一个定义在模块中的事件的条目。每一个条目包括标记和名字。

当编译器编译的源码时,你代码中定义的每件事都会引发一个条目的建立如上表所描述。元数据表也会被建立当编译器察觉类型,字段,方法,属性和事件是源代码引用。元数据建立包含一个引用表集合,保存了引用项目记录。下表显示了一些比较常见的引用元数据表。

Common Reference Metadata Tables(经常使用引用元数据表)

Metadata Reference Table Name(元数据引用表名称) Description(描述)
AssemblyRef(程序集引用) 模块引用的每一个程序集的条目。每一个条目包括须要绑定到的程序集的信息:程序集的名称(没有路径和扩张),版本号,区域,和公共关键口令(通常是从发布者公开的关键字生成的哈希值,识别引用程序集的发布者)。每一个条目也是一些标记和一个哈希值。这个哈希码倾向于做为应用程序集比特的校验码。CLR彻底忽略这个哈希值未来可能会继续这样作。
ModuleRef(模块引用) 实现这个模块引用的类型的每一个PE的条目。每一个条目包括模块的文件名称和扩张(没有路径)。此表用于绑定到类型实现不一样模块的调用汇编模块。
TypeRef(类型引用) 每一个被模块引用的类型有一个条目。每一个条目包括类型的名字和引用类型能够找到的地方。若是类型中实现另外一种类型,引用将会指出一个TypeRef条目。若是类型在同一个模块中实现,引用将会指出一个ModuleRef条目。若是类型调用程序集在另外一个模块中实现,引用将会指出一个ModuleRef条目。假如类型在不一样的程序中实现,引用将会指出一个AssemblyRef条目。
MemberRef(成员引用) 每一个被模块引用的成员(字段和方法,和属性和事件方法同样)有一个条目。每一个条目包括成员的名字和签名和指向TypeRef的条目。

还有不少表单我没有在上面两个表单中列出,而我只想给你一个编译器发布产生元数据信息种类的感受。以前我提到的有一个货运单元数据表集合;我会晚一点在这章讨论这些。

大量的工具容许你检测在托管PE文件中的元数据。我常用的仍是ILDasm.exe,IL反汇编程序。要看元数据表,执行如下命令行。

ILDasm Program.exe

这样ILDAasm.exe将会运行,加载Program.exe程序集。能够看到元数据在一个漂亮的、可读的表单里,选择View/MetaInfo/Show!菜单项(或者按Ctr+M)。如下信息将会出现。

===========================================================
ScopeName : Program.exe
MVID      : {42F16070-F580-468A-9925-70283A94D852}
===========================================================
Global functions
-------------------------------------------------------

Global fields
-------------------------------------------------------

Global MemberRefs
-------------------------------------------------------

TypeDef #1 (02000002)
-------------------------------------------------------
    TypDefName: Program.Program  (02000002)
    Flags     : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass] [BeforeFieldInit]  (00100101)
    Extends   : 01000001 [TypeRef] System.Object
    Method #1 (06000001) [ENTRYPOINT]
    -------------------------------------------------------
        MethodName: Main (06000001)
        Flags     : [Public] [Static] [HideBySig] [ReuseSlot]  (00000096)
        RVA       : 0x00002050
        ImplFlags : [IL] [Managed]  (00000000)
        CallCnvntn: [DEFAULT]
        ReturnType: Void
        No arguments.

    Method #2 (06000002) 
    -------------------------------------------------------
        MethodName: .ctor (06000002)
        Flags     : [Public] [HideBySig] [ReuseSlot] [SpecialName] [RTSpecialName] [.ctor]  (00001886)
        RVA       : 0x0000205e
        ImplFlags : [IL] [Managed]  (00000000)
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        No arguments.


TypeRef #1 (01000001)
-------------------------------------------------------
Token:             0x01000001
ResolutionScope:   0x23000001
TypeRefName:       System.Object
    MemberRef #1 (0a000012)
    -------------------------------------------------------
        Member: (0a000012) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        No arguments.

TypeRef #2 (01000002)
-------------------------------------------------------
Token:             0x01000002
ResolutionScope:   0x23000001
TypeRefName:       System.Runtime.Versioning.TargetFrameworkAttribute
    MemberRef #1 (0a000001)
    -------------------------------------------------------
        Member: (0a000001) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #3 (01000003)
-------------------------------------------------------
Token:             0x01000003
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyTitleAttribute
    MemberRef #1 (0a000002)
    -------------------------------------------------------
        Member: (0a000002) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #4 (01000004)
-------------------------------------------------------
Token:             0x01000004
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyDescriptionAttribute
    MemberRef #1 (0a000003)
    -------------------------------------------------------
        Member: (0a000003) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #5 (01000005)
-------------------------------------------------------
Token:             0x01000005
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyConfigurationAttribute
    MemberRef #1 (0a000004)
    -------------------------------------------------------
        Member: (0a000004) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #6 (01000006)
-------------------------------------------------------
Token:             0x01000006
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyCompanyAttribute
    MemberRef #1 (0a000005)
    -------------------------------------------------------
        Member: (0a000005) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #7 (01000007)
-------------------------------------------------------
Token:             0x01000007
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyProductAttribute
    MemberRef #1 (0a000006)
    -------------------------------------------------------
        Member: (0a000006) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #8 (01000008)
-------------------------------------------------------
Token:             0x01000008
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyCopyrightAttribute
    MemberRef #1 (0a000007)
    -------------------------------------------------------
        Member: (0a000007) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #9 (01000009)
-------------------------------------------------------
Token:             0x01000009
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyTrademarkAttribute
    MemberRef #1 (0a000008)
    -------------------------------------------------------
        Member: (0a000008) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #10 (0100000a)
-------------------------------------------------------
Token:             0x0100000a
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyCultureAttribute
    MemberRef #1 (0a000009)
    -------------------------------------------------------
        Member: (0a000009) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #11 (0100000b)
-------------------------------------------------------
Token:             0x0100000b
ResolutionScope:   0x23000001
TypeRefName:       System.Runtime.InteropServices.ComVisibleAttribute
    MemberRef #1 (0a00000a)
    -------------------------------------------------------
        Member: (0a00000a) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  Boolean

TypeRef #12 (0100000c)
-------------------------------------------------------
Token:             0x0100000c
ResolutionScope:   0x23000001
TypeRefName:       System.Runtime.InteropServices.GuidAttribute
    MemberRef #1 (0a00000b)
    -------------------------------------------------------
        Member: (0a00000b) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #13 (0100000d)
-------------------------------------------------------
Token:             0x0100000d
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyVersionAttribute
    MemberRef #1 (0a00000c)
    -------------------------------------------------------
        Member: (0a00000c) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #14 (0100000e)
-------------------------------------------------------
Token:             0x0100000e
ResolutionScope:   0x23000001
TypeRefName:       System.Reflection.AssemblyFileVersionAttribute
    MemberRef #1 (0a00000d)
    -------------------------------------------------------
        Member: (0a00000d) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  String

TypeRef #15 (0100000f)
-------------------------------------------------------
Token:             0x0100000f
ResolutionScope:   0x23000001
TypeRefName:       System.Diagnostics.DebuggableAttribute
    MemberRef #1 (0a00000e)
    -------------------------------------------------------
        Member: (0a00000e) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  ValueClass DebuggingModes

TypeRef #16 (01000010)
-------------------------------------------------------
Token:             0x01000010
ResolutionScope:   0x0100000f
TypeRefName:       DebuggingModes

TypeRef #17 (01000011)
-------------------------------------------------------
Token:             0x01000011
ResolutionScope:   0x23000001
TypeRefName:       System.Runtime.CompilerServices.CompilationRelaxationsAttribute
    MemberRef #1 (0a00000f)
    -------------------------------------------------------
        Member: (0a00000f) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        1 Arguments
            Argument #1:  I4

TypeRef #18 (01000012)
-------------------------------------------------------
Token:             0x01000012
ResolutionScope:   0x23000001
TypeRefName:       System.Runtime.CompilerServices.RuntimeCompatibilityAttribute
    MemberRef #1 (0a000010)
    -------------------------------------------------------
        Member: (0a000010) .ctor: 
        CallCnvntn: [DEFAULT]
        hasThis 
        ReturnType: Void
        No arguments.

TypeRef #19 (01000013)
-------------------------------------------------------
Token:             0x01000013
ResolutionScope:   0x23000001
TypeRefName:       System.Console
    MemberRef #1 (0a000011)
    -------------------------------------------------------
        Member: (0a000011) WriteLine: 
        CallCnvntn: [DEFAULT]
        ReturnType: Void
        1 Arguments
            Argument #1:  String

Assembly
-------------------------------------------------------
    Token: 0x20000001
    Name : Program
    Public Key    :
    Hash Algorithm : 0x00008004
    Version: 1.0.0.0
    Major Version: 0x00000001
    Minor Version: 0x00000000
    Build Number: 0x00000000
    Revision Number: 0x00000000
    Locale: <null>
    Flags : [none] (00000000)
    CustomAttribute #1 (0c000001)
    -------------------------------------------------------
        CustomAttribute Type: 0a000001
        CustomAttributeName: System.Runtime.Versioning.TargetFrameworkAttribute :: instance void .ctor(class System.String)
        Length: 77
        Value : 01 00 1c 2e 4e 45 54 46  72 61 6d 65 77 6f 72 6b >   .NETFramework<
                      : 2c 56 65 72 73 69 6f 6e  3d 76 34 2e 35 2e 31 01 >,Version=v4.5.1 <
                      : 00 54 0e 14 46 72 61 6d  65 77 6f 72 6b 44 69 73 > T  FrameworkDis<
                      : 70 6c 61 79 4e 61 6d 65  14 2e 4e 45 54 20 46 72 >playName .NET Fr<
                      : 61 6d 65 77 6f 72 6b 20  34 2e 35 2e 31          >amework 4.5.1   <
        ctor args: (".NETFramework,Version=v4.5.1")

    CustomAttribute #2 (0c000002)
    -------------------------------------------------------
        CustomAttribute Type: 0a000002
        CustomAttributeName: System.Reflection.AssemblyTitleAttribute :: instance void .ctor(class System.String)
        Length: 12
        Value : 01 00 07 50 72 6f 67 72  61 6d 00 00             >   Program      <
        ctor args: ("Program")

    CustomAttribute #3 (0c000003)
    -------------------------------------------------------
        CustomAttribute Type: 0a000003
        CustomAttributeName: System.Reflection.AssemblyDescriptionAttribute :: instance void .ctor(class System.String)
        Length: 5
        Value : 01 00 00 00 00                                   >                <
        ctor args: ("")

    CustomAttribute #4 (0c000004)
    -------------------------------------------------------
        CustomAttribute Type: 0a000004
        CustomAttributeName: System.Reflection.AssemblyConfigurationAttribute :: instance void .ctor(class System.String)
        Length: 5
        Value : 01 00 00 00 00                                   >                <
        ctor args: ("")

    CustomAttribute #5 (0c000005)
    -------------------------------------------------------
        CustomAttribute Type: 0a000005
        CustomAttributeName: System.Reflection.AssemblyCompanyAttribute :: instance void .ctor(class System.String)
        Length: 5
        Value : 01 00 00 00 00                                   >                <
        ctor args: ("")

    CustomAttribute #6 (0c000006)
    -------------------------------------------------------
        CustomAttribute Type: 0a000006
        CustomAttributeName: System.Reflection.AssemblyProductAttribute :: instance void .ctor(class System.String)
        Length: 12
        Value : 01 00 07 50 72 6f 67 72  61 6d 00 00             >   Program      <
        ctor args: ("Program")

    CustomAttribute #7 (0c000007)
    -------------------------------------------------------
        CustomAttribute Type: 0a000007
        CustomAttributeName: System.Reflection.AssemblyCopyrightAttribute :: instance void .ctor(class System.String)
        Length: 23
        Value : 01 00 12 43 6f 70 79 72  69 67 68 74 20 c2 a9 20 >   Copyright    <
                      : 20 32 30 31 35 00 00                             > 2015           <
        ctor args: ("Copyright ©  2015")

    CustomAttribute #8 (0c000008)
    -------------------------------------------------------
        CustomAttribute Type: 0a000008
        CustomAttributeName: System.Reflection.AssemblyTrademarkAttribute :: instance void .ctor(class System.String)
        Length: 5
        Value : 01 00 00 00 00                                   >                <
        ctor args: ("")

    CustomAttribute #9 (0c000009)
    -------------------------------------------------------
        CustomAttribute Type: 0a00000a
        CustomAttributeName: System.Runtime.InteropServices.ComVisibleAttribute :: instance void .ctor(bool)
        Length: 5
        Value : 01 00 00 00 00                                   >                <
        ctor args: ( <can not decode> )

    CustomAttribute #10 (0c00000a)
    -------------------------------------------------------
        CustomAttribute Type: 0a00000b
        CustomAttributeName: System.Runtime.InteropServices.GuidAttribute :: instance void .ctor(class System.String)
        Length: 41
        Value : 01 00 24 63 34 66 35 35  64 66 63 2d 63 38 63 66 >  $c4f55dfc-c8cf<
                      : 2d 34 66 64 37 2d 39 65  63 37 2d 37 62 63 35 37 >-4fd7-9ec7-7bc57<
                      : 31 64 65 65 65 35 63 00  00                      >1deee5c         <
        ctor args: ("c4f55dfc-c8cf-4fd7-9ec7-7bc571deee5c")

    CustomAttribute #11 (0c00000b)
    -------------------------------------------------------
        CustomAttribute Type: 0a00000d
        CustomAttributeName: System.Reflection.AssemblyFileVersionAttribute :: instance void .ctor(class System.String)
        Length: 12
        Value : 01 00 07 31 2e 30 2e 30  2e 30 00 00             >   1.0.0.0      <
        ctor args: ("1.0.0.0")

    CustomAttribute #12 (0c00000c)
    -------------------------------------------------------
        CustomAttribute Type: 0a00000e
        CustomAttributeName: System.Diagnostics.DebuggableAttribute :: instance void .ctor(value class DebuggingModes)
        Length: 8
        Value : 01 00 07 01 00 00 00 00                          >                <
        ctor args: ( <can not decode> )

    CustomAttribute #13 (0c00000d)
    -------------------------------------------------------
        CustomAttribute Type: 0a00000f
        CustomAttributeName: System.Runtime.CompilerServices.CompilationRelaxationsAttribute :: instance void .ctor(int32)
        Length: 8
        Value : 01 00 08 00 00 00 00 00                          >                <
        ctor args: (8)

    CustomAttribute #14 (0c00000e)
    -------------------------------------------------------
        CustomAttribute Type: 0a000010
        CustomAttributeName: System.Runtime.CompilerServices.RuntimeCompatibilityAttribute :: instance void .ctor()
        Length: 30
        Value : 01 00 01 00 54 02 16 57  72 61 70 4e 6f 6e 45 78 >    T  WrapNonEx<
                      : 63 65 70 74 69 6f 6e 54  68 72 6f 77 73 01       >ceptionThrows   <
        ctor args: ()


AssemblyRef #1 (23000001)
-------------------------------------------------------
    Token: 0x23000001
    Public Key or Token: b7 7a 5c 56 19 34 e0 89 
    Name: mscorlib
    Version: 4.0.0.0
    Major Version: 0x00000004
    Minor Version: 0x00000000
    Build Number: 0x00000000
    Revision Number: 0x00000000
    Locale: <null>
    HashValue Blob:
    Flags: [none] (00000000)


User Strings
-------------------------------------------------------
70000001 : ( 2) L"Hi"


Coff symbol name overhead:  0
===========================================================
===========================================================
===========================================================

幸运的是,ILDasm在合适的地方处理元数据表和联合信息因此你没必要转换表单行信息。例如,在以前提过的转储,你看当ILDasm显示一个TypeDef条目,在第一个TypeRef条目显示以前,对应的成员定义信息和它一块儿显示。

你不须要所有理解你看到的任何事情。重要的是记住Program.exe包含一个名字叫作Program的TypeDef。这个类型识别一个从System.Object(一个被其它程序集引用的类型)继承的公共密封类。Program类型也定义两个方法:Main和.ctor(一个构造器)。

Main是一个公共的、静态的方法它的代码是IL(相对于本地CPU代码,好比x86)。Main没有返回类型也没有参数。构造器方法(老是以.ctor的名字出现)是公共的,它的代码也是IL。构造器没有返回类型,没有参数,有一个this指针,当方法被调用时会构造一个对象的内存,this指针会指向它。

我强烈支持你体验ILDasm。它会为你展现大量的信息,你看到的你会理解的更多,你将更理解CLR和它的能力。正如你将看到的,我在这本书中使用ILDasm至关多。

只是为了有趣,让咱们看一些关于Program.exe程序集的统计。当你选择ILDasm的View/Statistics菜单项,会显示如下信息。

File size            : 4608
 PE header size       : 512 (496 used)    (11.11%)
 PE additional info   : 1535              (33.31%)
 Num.of PE sections   : 3
 CLR header size     : 72                 ( 1.56%)
 CLR meta-data size  : 1508               (32.73%)
 CLR additional info : 0                  ( 0.00%)
 CLR method headers  : 2                  ( 0.04%)
 Managed code         : 20                ( 0.43%)
 Data                 : 2048              (44.44%)
 Unaccounted          : -1089             (-23.63%)

 Num.of PE sections   : 3
   .text    - 2048
   .rsrc    - 1536
   .reloc   - 512

 CLR meta-data size  : 1508
   Module        -    1 (10 bytes)
   TypeDef       -    2 (28 bytes)      0 interfaces, 0 explicit layout
   TypeRef       -   19 (114 bytes)
   MethodDef     -    2 (28 bytes)      0 abstract, 0 native, 2 bodies
   MemberRef     -   18 (108 bytes)
   CustomAttribute-   14 (84 bytes)
   Assembly      -    1 (22 bytes)
   AssemblyRef   -    1 (20 bytes)
   Strings       -   630 bytes
   Blobs         -   272 bytes
   UserStrings   -     8 bytes
   Guids         -    16 bytes
   Uncategorized -   168 bytes

 CLR method headers : 2
   Num.of method bodies  - 2
   Num.of fat headers    - 0
   Num.of tiny headers   - 2

 Managed code : 20
   Ave method size - 10

这里你能够看到文件大小(以字节为单位)和组成文件的各部分大小(以字节和百分比为单位)。从这个很小的Program.cs应用程序能够看出,文件中大部分是PE头文件和元数据。事实上,IL代码仅仅占用了20字节。固然,随着应用程序增大,它将重用它的大多数类型和引用其它类型和程序集,当和总体的文件大小相比的时候元文件和头文件信息缩减了。

注意  顺便说一下,ILDasm.exe有一个影响文件大小的漏洞。特别的,你不能信任未包含在数目中的信息。

Combining Modules to Form an Assembly(组合模块造成一个程序集)

在以前章节讨论过的Program.exe文件不止是带有元数据的PE文件;它也是一个程序集。一个程序集是一个或多个文件包含类型定义、资源文件的一个集合。其中的一个程序集文件选择持有一个载货单。载货单是另外一个元数据表格的集合主要包含程序集的一部分文件的名字。它们也描述程序集的版本,区域,发布者,公共导出类型,和组成程序集的全部文件。

CLR在程序集集合上工做;CLR老是先加载包含载货单元数据表格的文件而后使用载货单获取在程序集中的其它文件的名字。这里是一些你应该记住的程序集集合特征:

*一个程序集定义可重用类型。

*一个程序集经过版本号标记。

*一个程序集能够有与之相关的安全信息。

一个程序集的特有文件没有这些属性——指望文件包含载货单元数据表格。

程序集,版本,安全和使用类型,你必须把它们放在模块中由于它们是程序集的一部分。在大多数案例中,一个程序集由一个单独的文件组成,就像以前的Program.exe例子同样。然而,一个程序集也能够由多个文件组成:一些带有元数据的PE文件和一些资源文件好比:.gif或.jpg文件。它能够帮助你考虑一个程序集是合理的EXE仍是一个DLL。

我肯定大家大多数人读到这都很疑惑为何微软引进程序集概念。缘由是一个程序集容许你从逻辑和物理的概念上解耦可重用类型。例如,一个程序集能够又几个类型组成。你能够把经常使用的类型方法放到一个文件中不经常使用的放到另外一个文件中。假如你的程序集是经过Internet下载部署,不经常使用类型可能永远也不会下载到客户端若是客户端从不访问那个类型。例如,一个独立的软件供应商(independent software vendor,ISV)专攻UI控件可能选择在一个分离的模块(知足微软的商标要求)中实现Active Accessibility类型。只有须要额外访问性特征的用户才须要下载这个模块。

在应用程序的配置文件中经过指定codeBase元素(在第三章讨论)你能够配置一个应用程序下载程序集文件。codeBase元素标识一个URL指向能够找到一个程序集全部文件的地方。当尝试下载一个程序集的文件,CLR获取codeBase的元素的URL而后检查机器的下载缓存文件是否是已经有了。若是是,文件会被加载。若是文件再也不缓存中,CLR从URL指向的位置下载文件到缓存。假如文件找不到,CLR在运行时抛出一个FileNotFoundException异常。

我指出三个使用多程序集的缘由:

*在分隔的文件之间直接分配你的多个类型,容许文件逐步下载就像Internet下载场景描述的那样。把多个类型分配到隔离的文件同时容许为你的应用程序部分或逐步打包和部署。

*你能够添加资源或者数据文件到你的程序集。例如,你能够有一个类型用于计算一些保险信息。这个类型可能须要访问一些保险精算的表格来作计算。代替把保险精算表格嵌入到你的源代码,你可使用一个工具(好比程序集连接者,AL.exe,稍后讨论)使数据文件被认为是程序集的一部分。顺便提一下,着这个数据文件能够是任何格式的——一个文本文件,一个微软Excel电子表格,一个微软Word表,或者你喜欢的不管什么——只要你的应用程序知道怎么转换文件的内容。

*你能够建立由不一样语言实现的类型组成的程序集。例如,你能够实现一些C#的类型,一些微软Visual Basic的类型,和一些由其它语言实现的。当你编译C#源码类型编译器生成一个分离的模块。接下来你可使用一个工具把全部的模块组合成一个程序集。对于使用程序集的开发者,程序集呈现的只是一堆类型;开发者甚至不知道程序集使用了不一样的语言开发。顺便提一下,假如你喜欢,你能够运行ILDasm.exe并把它所有转为IL源码文件。ILAsm.exe将会产生一个包含全部类型的文件。这个技术要求你的源码编译器只生成IL代码。

相关文章
相关标签/搜索