.NET平台初窥
在C#语言和.NET平台之前,针对Windows家族的软件开发主要使用COM,也就是基于组建模型的开发,例如C++程序员可以创建一个COM类库供VB程序员使用。COM的跨语言特性虽然有用,但是他开发复杂和脆弱,且只能针对Windows家族的操作系统。虽然很多的应用程序使用了COM获得了成功,但是如今的操作系统应用程序,web网站,操作系统服务和各种可重用的类库都是通过使用.NET平台进行开发。
C#和.NET平台在2002年第一次推出,提供了一种更加有利的,灵活的和简单的开发模型。.NET平台是一种可以在Windows家族和其他操作系统如Mac OS X和Unix/Linux操作系统上进行开发的软件平台,具有如下特性:
与既有的代码兼容;支持多种编程语言;被所有.NET语言共享的公共运行引擎;语言集成,.NET支持跨语言继承和异常处理,还有跨语言调试代码,例如你可以定义一个C#代码类,而使用VB继承这个类;更简单的部署模型,与COM不同,.NET类库不是相COM一样注册在系统注册表中,.NET平台允许不同版本的同一个*.dll存在同一个机器上。
.NET平台的组成
.NET平台主要由三个概念组成,CLR,CTS和CLS。Common Language Runtime也就是CLR是负责定位,加载和管理.NET对象的,同时还负责许多底层细节的处理,例如内存管理,应用程序承载和线程调度以及安全检查等。Common Type System也就是CTS用来指定所有可用的数据类型和所有支持的编程结构,以及他们之间的交互和是如何使用.NET元数据格式进行表示。.NET支持的语言并不一定会完全支持所有的CTS规范。Common Language SpecificationCLS定义了所有的被.NET支持的语言所共同支持的类型和编程结构。也就是如果你创建了一个符合CLS的.NET类型,那么就能够保证其他的.NET语言可以与他进行交互。我们可以很轻易的使用C#编译器来检查我们的代码是否支持CLS规范。
除了CLR和CTS,CLS之外,.NET平台还提供了基础类库,这个类库面向所有.NET编程语言,这个类库不仅仅封装了许多出事功能,例如线程,文件IO,图形绘制系统和硬件交互等,还提供了许多应用程序需要用到的服务,如ASP.NET,WCF,WPF等,在起初的.NET版本中提供的特性有不需要指针操作,自动的内存回收机制,正规的类构造语法,简单的自定义类型运算符重载,支持基于属性的编程;在2.0的版本中又添加了泛型,匿名方法,多文件定义类等特;在.NET3.5版本中继续添加了强类型查询LINQ,支持匿名类型,支持既有类型的扩展(不使用派生类使用扩展方法),lambda运算符和新的对象初始化语法等,在4.0版本中继续添加了可选方法参数,动态成员查找dynamic关键字,更简单的泛型操作;在最新的版本4.5中增加了新的关键字async和await使得并发编程更加容易。
关于C#编程语言需要更加清楚的一点是他可以生成针对.NET运行时运行的代码,也就是托管代码。所有针对.NET运行时的代码都是托管代码,包含托管代码的二进制单元成为程序集,相反,不直接支持.NET运行时的代码成为非托管代码。
.NET编程语言
C#并不是唯一的.NET支持的语言,还有其他的语言如VB,C++/CLI,JavaScript和F#,其中F#是完全的函数语言functional language,同时还支持OOP类型和.NET基础类库,如果感兴趣可以去F#的主页了解:http://msdn.microsoft.com/fsharp。除了Microsoft提供的托管语言,还有针对Smalltalk,Ruby,Python和COBOL,Pascal的编译器。在网站www.dotnetlanguages.net上点击顶部的资源连接,可以找到.NET编程语言列表和相关的编译器连接。
.NET程序集初窥
不管使用什么语言,.NET的二进制文件除了使用相同的扩展文件名作为非托管的Windows二进制文件之外,他们没有任何的内在相似指出。.NET的二进制文件不针对平台而是一种基于平台的Intermediate Language IL和类型元数据。由.NET编译器生成的dll或者exe文件通常称之为程序集,里面包含的是CIL,Common Imediate Language,类似于Java二进制码的一种中间语言,除非在必要的时候是不会被编译成为针对运行平台的可运行代码。这里的必要情况是指.NET运行时需要调用他的时候。除此之外程序集还包含了元数据,用来描述程序集内的所有类型的细节,这些内容是由编译器在编译的时候生成的。最后程序集还包含了一个用来描述程序集本身信息的元数据清单,例如当前的版本,本地化信息以及运行时需要引用的其他程序集的列表信息等。
下面我们来具体看一下,下面的例子是一个C#代码的计算器,留意一下Calc类的Add方法:
在使用C#编译器编译之后会生成一个包含了自身清单信息,CIL和元数据描述信息的exe程序集文件,如果使用ildasm.exe来打开这个程序集我们可以看到代表Add方法的CIL信息如下:
使用CIL的一个好处就是便于语言的集成,因为所有的.NET语言的编译器所生成的CIL代码大致相同,因此对于不同的语言的二进制代码非常便于相互交互,另外CIL是不确定平台的,而.NET Framework也是不确定平台的,因此就提供了类似于Java的跨平台性。
在CIL使用之前必须由JIT Just In Time进行编译成机器码,.NET运行时使用JIT编译器针对不同的CPU环境进行编译和优化,并且进行缓存,这样下一次再对程序集进行使用的时候就可以直接调用,而不用再次进行JIT编译了。
程序集中的元数据信息用来描述程序集中的类型信息以及类型中包括的成员信息,这些信息是由编译器生成,如上面的C#代码所生成的程序集中的元数据代码如下:
元数据经常被.NET运行环境所使用,以及各种开发工具,如编译器的智能感知,对象浏览工具,调试工具和C#编译器工具等,同时元数据还是WCF的核心技术,包括反射,延迟绑定和对象序列化等。
最后程序集中的自描述清单信息描述了程序集本身的信息,包括需要使用的外部程序集,版本信息, 版权等,同元数据一样,也是通过编译器来生成的,下面就是上面的C#程序集中的自描述信息:
理解公共类型系统
一个程序集中包含了不同的类型,类型只是类,接口,结构,枚举和委托中的一种,CTS是一种类型定义的规范,可以使得定义的类型能够被公共运行时承载。在mscorlib.dll程序集中定义了基本的数据类型,这些数据类型也可以使用唯一的关键字来表示,这里关键字仅仅是对基本类型的一种简写:System.Byte byte;System.SByte sbyte;System.Int16 short;System.Int32 int;System.Int64 long;System.UInt16 unit;System.UInt32 uint;System.UInt64 ulong;System.Single float;System.Double double;System.Object object;System.Char char;System.String string;System.Decimal decimal;System.Boolean bool。
理解公共语言标准
CLS是描述所有.NET语言必须支持的最小和完整的特性和规范,用来使其能够被CLR支持,同时也可以与其他.NET语言进行交互。每个规则都有自己的简单明明并且描述了这个规则如何影响编译器和如何影响与其他语言之间的交互。CLS标准仅仅规范类型的的定义并不会涉及到类型的逻辑实现,如下面的C#方法Add,因为参数和返回类型使用了无符号类型,因此不符合CLS规范:
但是如果仅仅在内部使用无符号类型那么就是符合CLS规范的,那么这么方法便可以被其他的.NET语言所调用:
在C#中提供了很多不符合CLS规范的语法,可以使用[assembly: CLSCompliant(true)]让编译器对代码进行差是否符合CLS规范。
理解公共语言运行时
运行时是一段编译的代码执行时需要的各项服务的集合。.NET平台的运行时提供了一个单一的,完整定义的编译层相所有的.NET语言提供了支持,也就是.NET运行时是被所有的.NET语言所共享的。CLR的核心是通过mscoree.dll也就是Common Object Runtime Execution Engine表示的,当一个引用的程序集需要被使用的时候,mscoree.dll被自动加载,与此同时加载所需的程序集到内存中。运行时引擎负责以下几个方面的工作,首先也是最重要的它负责代理找到程序集的位置并且在程序集中根据元数据来找到所需的类型,然后 CLR将类型加载到内存,编译相关的CIL到针对与此平台的结构,执行必要的安全检查然后执行代码。
为了能够加载自定义的程序集并且创建自定义类型,CLR还会与.NET的基础类库中的类型进行交互。虽然整个的基础类库是划分成多个程序集,最关键的是mscorlib.dll,包含了大量的核心类型,当你创建.NET解决方法的时候会自动加载这个程序集。
程序集、命名空间和类型识别
命名空间用来绑定相关的类型到同一个或者分散到多个程序集中。我们可以认为System.Console表示了一个名字为Console的类,这个类在System命名空间下,但是是.NET运行时并不会这么理解,他还是会理解成为一个名为SystemConsole的类。虽然我们使用using关键字来简化完整的类名称书写,但是这并不能改变CIL使用的是完整的命名名称的事实。除了使用using关键字之外还需要告诉C#编译器所引用的程序集的名称和引用路径。这样才能够找到所需要被引用的类型。
使用ildasm.exe探索程序集
Intermediate Language Disassembler工具ildasm.exe是一个跟随着.NET Framework 4.5 SDK一起安装的巩固,可以查看.NET程序集的内部信息和内容,包括自身的清单信息,CIL代码和类型元数据。能够让程序员更加轻松的深入C#代码与CIL之间的映射,最终帮助程序员更好的理解.NET平台的工作机制。我们可以通过命令行输入ildasm,然后回车来启动ildasm.exe程序,然后查看相关的程序集信息。
.NET的跨平台本质
.NET的程序系可以在非Windows平台上开发和运行,这涉及到了CLI Common Language Infrastructure。当微软发布.NET平台的时候还一起发布了C#和CIL语言的语法,.NET程序集的格式,核心.NET命名空间以及虚拟.NET运行引擎的机制。这些文档允许了任何第三方开发针对其他操作系统和处理器的.NET平台。
Mono和Portable .NET都提供了ECMA标准的C#编译器,.NET运行引擎和代码范例,文档还有各种开发工具等,能够将.NET平台移植到其他的操作系统上。