摘 要数据库
.NET Framework 究竟是什么?公共语言运行时和 .NET Framework 类库分别指的是什么东西?CLR、 CLS、 CTS、FCL等这些又是什么?为何出现程序集的概念?它与动态连接库的区别是什么?什么是强命名程序集?如何签名及部署程序集?这一章将帮助您学习和了解其中的秘密。编程
第一节 .NET Framework是什么?缓存
.NET Framework(.NET框架),是由微软提出并实施的一个集成在Windows中的组件。它基于虚拟机技术实现的平台无关性的软件开发平台,它以语言运行库(CLR)为平台支持多种语言开发,如C#、VB、托管C++等,以强制的类型安全为基础实施运行在托管环境中来达到代码安全和隔离运行、提供对内存的自动化管理、线程的优化切换、提供一个统一的面向对象编程模型。安全
.NET Framework环境服务器
.NET Framework 包含两大核心组件:公共语言运行时和.NET Framework类库。数据结构
第二节 公共语言运行时架构
公共语言运行时 英文名Common Language Runtime,简称 CLR。它是一个相对开放的运行平台,可供多种语言(C#、VB等)使用的运行时。CLR拥有一组核心功能,包括:内存管理、线程执行、程序集加载、异常处理、强制类型安全等,这些功能对全部面向CLR的语言都支持。在程序运行的时候,CLR对编码语言是未知的,不管任何语言,只要它的编译器是面向CLR的就能够。像微软本身的C#编译器、VB编译器、F#编译器等。固然你也能够实现本身的编译器,但你的编译器必须是面向CLR的。编译器将对源代码进行语法验证和分析,最终生成托管模块(Managed Module),进而一个传说中的程序集诞生了。并发
托管模块 是一个标准Microsoft Windows可移植执行体,它多是32位(PE32)文件,也多是64位(PE32+)文件。托管模块有以下几部分组成:框架
PE32/PE32+ 头 标准的 Windows PE文件头。若是文件头使用PE32格式,则此文件只能在Windows 的32位或64位版本上运行;若是文件头使用PE32+格式,则此文件只能在Windows 的64位版本上运行。另外,文件头还可能包含与本地CPU代码相关的信息。编译器在编译时,可经过编译平台/platform开关来指定该程序集包含一个PE32头或PE32+头。在Visual Studio中能够对目标平台进行选择,如图:
CLR头 包含了标志此模块为一个托管模块的基本信息,如CLR版本、托管模块入口方法、模块的元数据、资源等。
元数据 元数据是一组数据表,它是一个二进制块。包含三类数据表:一个表描述了与此模块对应的源代码中定义的类型、成员,这是定义表;另外一个表描述了此代码所引用的其余类型(成员)列表,这是引用表,还有一类是清单表。常见的元数据定义表有ModuleDef、TypeDef、MethodDef、FieldDef、ParamDef、PropertyDef、EventDef。常见的引用表有AssemblyRef、ModuleRef、TypeRef、MemberRef。
IL代码 也是中间语言。编译器编译源代码时生成的中间代码,在执行环境中,这些IL代码将被CLR的JIT编辑器翻译成CPU能识别的指令,供CPU执行。
在执行时,CLR是经过程序集与托管模块进行沟通的。程序集是一个或多个托管模块和资源文件的逻辑分组,(它就至关于一个省份组织,它划分了一部分人和地域资源)。程序集是由编译器生成,最终生成的多是EXE或DLL文件。在程序集内有一个清单,其描述了程序集内的文件列表,如托管模块、jpeg文件、XML文件等。CLR可以经过程序集内模块中的自描述信息来肯定要执行此程序集中代码时所依赖的其余对象。
动态连接库(Dynamic-Link Libraries,简称DLLs),就是一个可执行模块,其扩展名为.dll,它是基于C++,Delphi等语言生成的。模块中包含了能够被其余应用程序或其余dll使用的例程和资源。dll没有一般的主程序,但它有多个执行入口。DLLs的特色在于它的代码是在运行期动态地连接到调用它的程序中的。
.NET Framework中的 程序集的扩展名dll与动态连接库中的dll无非是同名罢了,是彻底不相同的两个概念。
下面以一个控制台程序来模拟CLR加载及程序运行过程。示例代码:
View Code
(1)在Windows中要运行一个EXE文件,Windows会首先检查这个EXE文件的头,以肯定该文件是32位、64位仍是WoW64(Windows on Windows64技术,运行32位程序运行在64位版本的Windows环境中),进而建立相应的进程,而后在进程的地址空间中加载MSCorEE.dll的相应x86、x64、IA64版,紧接着进程的主线程调用MSCorEE.dll中的一个CorBindToRuntimeEx函数,这个函数的主要功能就是加载CLR。CorBindToRuntimeEx函数定义:
HRESULT CorBindToRuntimeEx (
[in] LPWSTR pwszVersion,
[in] LPWSTR pwszBuildFlavor,
[in] DWORD startupFlags,
[in] REFCLSID rclsid,
[in] REFIID riid,
[out] LPVOID* ppv
);
pwszVersion 描述要加载的 CLR 的版本。
pwszBuildFlavor 字符串,指定是加载 CLR 的服务器版本仍是工做站版本。值:svr 和 wks。
startupFlags。STARTUP_FLAGS 枚举值的组合。这些标志控制并发垃圾回收、非特定于域的代码以及 pwszVersion 参数的行为。若是未设置标志,则默认值为一个域。
rclsid 实现ICorRuntimeHost 接口的 coclass 的 CLSID。支持的值为 CLSID_CorRuntimeHost或 CLSID_CLRRuntimeHost。
Riid 请求自 rclsid 接口的 IID。支持的值为 IID_ICorRuntimeHost 或 IID_ICLRRuntimeHost。
Ppv 返回的指向 riid 的接口指针。
(2)CLR加载完成后,在执行Main方法前CLR会检查Main 方法所引用的全部类型且在内部初始化一个数据结构来记录被引用类型的内的每一个方法的入口。因为程序集内包含了元数据和IL,接下来CLR的主要工做就是要先找到WriteLine方法的IL,用JIT编译器对其进行验证(Verification),把IL翻译成本地CPU指令,指令被保存在动态内存中。接着进行压栈,执行第一个WriteLine方法。若是下次要再次执行WriteLine方法,因为第一次已经对该方法进行验证及编译(CPU指令),因此此次直接执行CPU指令便可。因此一个类型或方法,只有在第一次执行时有性能损失,之后对该类型的调用是直接运行CPU指令,性能飞速提升。
第三节 .NET Framework类库
Framework 类库 英文名 Framework Class Library 简称 FCL。是一组与CLR紧密集成的可重用的面向对象的类型(程序集)集合。它包含有成千上万个能使咱们的托管代码从中导出的类型。它不只提供了一些常见的编程功能,如字符串处理,数据库链接等,还提供了一些高级开发,如线程同步,反射,垃圾回收等功能;它不只公开了一些UI库,如Windows from 、Web窗体、Silverlight等,还公开了一些面向服务的编程,如WebService,、Windows 服务、WCF等。
因为类库提供了太多的类型,因此它们以命名空间为组织划分到不一样的dll中。例如:
System命名空间 包含了每一个应用程序都要用到的全部基本类型。
System.IO命名空间 包含了执行流I/O 以及目录浏览的类型等。
基类库 英文名 Base Class Library 简称BCL。它封装了大量的基础功能,如文件操做、图形操做、网络链接、XML文档解析、安全加密,等等。
第四节 通用类型系统
因为在执行时CLR对它支持的语言未知,(固然,这些语言必须是面向CLR)即CLR无论要执行的代码是 C# 编写仍是VB编写。CLR围绕类型展开,只要其编码语言是面向CLR的,它们就能够相互交流,要想达到相互认识和理解,必须制定类型的定义和行为及状态。这个对类型的定义和行为的描述就是通用类型系统。英文名Common Type System 简称CTS。
CTS规定一个类型能够包含零个或多个成员,这些成员包括:字段,属性,方法,事件等,另外还能够对成员的访问规则进行控制,如public ,private,internal等。
第五节 通用语言规范
公共语言规范 英文名Common Lahguage Specification 简称 CLS。
CLR集成支持了全部面向CLR的语言,容许在一种语言中使用另外一种语言建立的对象,但因为各类语言自己的特性,好比有些语言不支持无符号整数,有些不区分大小写。若是要想作到本身公开的类型能被其余语言所识别,则就要尽量按照其余语言所支持的特性且本身也支持的特性去构造。CLS详细定义了一个各类面向CLR共有的最小功能集。如图:
第六节 通用语言基础架构
通用语言基础架构(Common Language Infrastructure,简称CLI)是一个开放的技术规范。维基百科解释:定义了构成.NET Framework基础结构的可执行码以及代码的运行时环境的规范,它定义了一个语言无关的跨体系结构的运行环境,这使得开发者能够用规范内定义的各类高级语言来开发软件,而且无需修正便可将软件运行在不一样的计算机体系结构上。
CLI有时候会和CLR混用。但严格意义上说,这是错误的。由于CLI是一种规范,而CLR则是对这种规范的一个实现。
第七节 强命名程序集及部署
在通过编译器生成程序集后,若是只是一个应用程序使用该程序集,则直接将该程序集复制到目标目录便可,这就是私有程序集的部署。若是一个程序集有多个程序使用,则须要把这个共用的程序集放到一个公共的目录。像全局应用程序域里的程序集就是公用的。可是,若是有多个部门或公司开发的具备相同名称的程序集放到同一个目录,这就可能不太现实,由于后来部署上去的DLL会覆盖先前一次部署的DLL,很显然以文件名来区分程序集是不可取的。CLR必须提供对程序集进行惟一性验证办法。这就是“强命名程序集”。一个强命名程序集用四个属性共同对一个程序集进行标识,这四个属性是:文件名(不包括扩展名)、版本号、语言文化特性和一个公钥(使用公钥派生出的一个小的Hash 值,公钥标记)。以下一个程序集文件:
“commonTypes,Version=2.0.2.1029,Culture=neutral,PublicKeyToken=c55b39c999a8888d”
强命名程序集能够防被篡改,也能够将强命名程序集部署到全局程序集缓存。
(1)使用SN生成密钥,命令行导航到VS安装目录,使用SN命令便可生成一个密钥,以下:
(2)将已经生成的MyApp.snk复制到项目工程下,以下图,固然也能够放到其余目录:
(3) 设置项目的属性签名
(4) 从新生成项目便可获得具备强命名的程序集。
(5) 若是一个程序集是由多个应用程序使用,必须把它部署到一个让CLR能检测到的已知目录,那这个目录就是全局程序集缓存GAC。.NET4.0的GAC位于:
C:\Windows\Microsoft.NET\Assembly
必须使用GACUtil.exe工具来完成程序集的部署工做。该命令有两个重要的开关:
/i 将某个程序集安装到全局程序集缓存中
/u 将某个程序集从全局程序集缓存中卸载
安装示例:载该程序集。如:
<codeBase
version="2.0.0.0" href="http://www.roojune.com/MyApp.dll"/>
gacutil /i 强命名程序所在的绝对路径
例如:D:\>gacutil /i C:\MyApp.dll
除了将强命名程序集部署到GAC之外,还能够以私有方式部署程序集,例如将其部署到网络上,在config中配置当程序运行时再加。