初学.NET肯定会有一系列的疑问,比如(以下为自己的疑问):
1) 何为. NET框架,它都包含哪些东西?
2) 程序集是什么,它是如何在CLR(通用语言运行时)中运行的?
3) C#与VB.NET同属于.NET平台,它们之间的根本联系和区别,为何他们之间的程序集能互相调用(如果创建一种新型的面向. NET的语言,要遵循什么)?
想要明白如上问题,就需要弄清楚CIL(通用中间语言)、CLR(通用语言运行时)、CTS(通用类型系统)、CLS(通用语言规范)等等的概念,下面是自己看了一些他人的文章后进行的简单总结。
首先通俗地理解一下.NET平台、.NET框架(Framework)的概念
“平台”(这里指软件技术平台,下面都指的是这个)就是能够独立运行并自主存在,为其所支撑的上层系统和应用提供运行所依赖的环境。提取一下就是,平台是一个环境。
我的通俗理解.NET平台是.NET应用与操作系统之间的一个中介,首先它为.NET应用运行提供了环境,其次它为.NET应用与操作系统之间起到了“解耦”的作用,使得平台上层的应用不依赖与操作系统(的机器指令集)。至于如何解耦,要看它的编译过程,下面会进行解释。
框架就好似某种应用的半成品,是前人根据经验开发的可复用的一组组件,供你选用,然后添血加肉完成你自己的系统。其思想与设计模式有些相似,框架是代码复用,设计模式是设计复用。框架又好似提供的一组规范,它规范应用系统的开发与部署,众所周知的J2EE框架就是定义了13个规范。相类似,NET Framework也提供了很多规范,下面会进行介绍。
粗略地说,一个.NET应用是一个运行于.NET Framework之上的应用程序。或者,一个.NET应用是一个使用.NET Framework类库来编写,并运行于公共语言运行时CLR(通用语言运行时)之上的应用程序。下面开始解决上面提出的问题:
程序集及其运行
首先引出两个概念CIL——通用中间语言、CLR——通用语言运行时两个概念(具体概念看百度百科)。
我们知道,普通的无平台应用(例如:VB应用程序)经过预编译、编译、汇编、链接几个步骤后,最终生成的可执行文件中就已经包含了本地处理器的代码,支持它运行的是操作系统和本地的机器指令集。
在.NET框架下,高级语言(例C#)经过编译后生成的结果文件被称做程序集,其后缀名是.dll(类库)或.exe(可执行程序,控制台应用程序编译结果)。而程序集并不是二进制机器码,是不能直接运行的,需要经过CLR(通用语言运行时)的即时编译才能生成被操作系统所识别的机器码。
下面我们用C#和VB.NET分别写两个相同控制台应用程序,都定义一个字符串“hello world”,然后输出:
C#:
VB.NET:
然后经过编译,分别生成相应的程序集.exe文件,下面我们用vs自带的反编译工具-IL DASM(目录:开始-- >vs2010-- >Windows SDK Tools -- >IL 反汇编程序)分别打开上面生成的程序集。
C#程序集:
VB.NET程序集:
对比两个程序集文件,可以发现两者的代码几乎完全一致。
上面用IL DASM打开的文件中的类似汇编的代码即为CIL-通用中间语言。可以看到VB.NET与C#,编译后生成的程序集的格式是相同的;当程序所实现的功能相同时,程序集所包含的CIL代码也是类似的。由此可得下图:
上面提到了程序集(CIL)并不是CPU可以直接执行的本地机器语言。这种语言还需要.NET运行时(CLR)环境的支持,在执行之前,进行一个被称为即时编译的二次编译过程,才能转变成计算机可以识别的指令。
CIL也是一种程序语言,它是比C#低级,比机器码高级的一种中间码语言,类似Java中的.Class文件。从前面截图可知CIL是一种基于堆栈的语言,同时,它提供了class、interface、继承、多态等诸多面向对象的语言特性,因此它又是完全面向对象的语言。如果愿意,甚至可以直接编写CIL代码,并且使用CIL的编译工具IL ASM(IL Assembler,IL汇编程序)来对它进行编译。只不过,和大多数低级语言一样,这种方式会使开发效率会变得很低。
C#源程序在被编译为程序集以后,就独立于C#,因此程序集可以由其他种类的语言所调用;同时,因为程序集并没有包含本地机器的指令,所以它与具体的机器类型也分隔开了,可以被装有.NET框架的任何机器运行。
C#与VB.NET的根本联系与区别
(下文大部分引用一些书籍或博文)
这里要引入CTS——公共类型系统、CLS——公共语言规范两个概念。
设想我们如何开发一套类似C#或VB.NET的新的语言(编译后生成CIL代码,可以在.NET环境下运行)?
要开发的新语言相当于CIL的高级语言版本,所以实际上要做什么并不是由新语言决定的,而是由CIL来决定的。因此,需要一套CIL的定义、规则或标准。这套规则定义了我们的语言可以做什么,不可以做什么,具有哪些特性。这套规则就称作CTS(Common Type System,公共类型系统)。任何满足了这套规则的高级语言就可以称为面向.NET框架的语言。C#和VB.NET不过是微软自己开发的一套符合了CTS的语言,实际上还有很多的组织或团体,也开发出了这样的语言,比如Delphi.Net、FORTRAN等。
CTS规定了可以在语言中定义的数据类型、访问级别比如Private、Public、Family(C#中为Protected)、Assembly(C#中为internal)、Family and assembly(C#中没有提供实现)、Family or assembly(C#中为protected internal)。
CTS还定义了一些约束,例如,所有类型都隐式地继承自System.Object类型,所有类型都只能继承自一个基类。从CTS的名称和公共类型系统可以看出,不仅C#语言要满足这些约束,所有面向.NET的语言都需要满足这些约束
上面提到了,C#并没有提供Family and assembly的实现,C#中也没有全局方法(Global Method)。换言之,C#只实现了CTS 的一部分功能。也就是说,CTS规范了语言能够实现的所有能力,但是符合CTS规范的具体语言实现不一定要实现CTS规范所定义的全部功能。
显然,由于CIL是.NET运行时所能理解的语言,因此它实现了CTS的全部功能。虽然它是一种低级语言,但是实际上,它所具有的功能更加完整。C#语言和CIL的关系,可以用如下表示:
既然已经理解了CTS是一套语言的规则定义,就可以开发一套语言来符合CTS了。假设这个语言叫做B#,它所实现的CTS非常有限,仅实现了其中很少的一部分功能,它与CTS和C#语言的关系可能如下:
那么现在就有一个问题:由C#编写的程序集,能够引用由B#编写的程序集吗?答案显然是不能。虽然C#和B#同属于CTS旗下,但是它们并没有共通之处。因此,虽然单独的B#或C#程序可以完美地在.NET框架下运行,但是它们之间却无法相互引用。
如果B#项目期望其他语言类型的项目能够对它进行引用,就需要B#中公开的类型和功能满足C#语言的特性,即它们需要有共通之处。B#中不公开的部分(private、internal、protected)是不受影响的,可以使用独有的语言特性,因为这些不公开的部分本来就不允许外部进行访问。因此,如果B#想要被C#所理解和引用,它公开的部分就要满足C#的一些规范,此时,它与CTS和C#语言的关系就会变成如下:
如果世界上仅有C#和N#两种语言就好办了,把它们共同的语言特性提取出来,然后要求所有公开的类型都满足这些语言特性,这样C#和N#程序集就可以相互引用了。可问题是:语言类型有上百种之多,并且.NET的设计目标是实现一个开放的平台,不仅现有的语言经过简单修改就可以运行在.NET框架上,后续开发的新语言也可以,而新语言此时并不存在,如何提取出它的语言特性?因此又需要一套规范和标准来定义一些常见的、大多数语言都共有的语言特性。
对于未来的新语言,只要它公开的部分能够满足这些规范,就能够被其他语言的程序集所使用。这个规范就叫做CLS (Common Language Specification,公共语言规范)。很明显,CLS是CTS的一个子集。那么VB.NET、C#、B#的关系就可表达为:
如果利用C#开发的一个程序集的公开部分仅采用了CLS中的特性,那么这个程序集就叫做CLS兼容程序集(CLScompliant assembly)。显然,对于上面提到的FCL框架类库,其中的类型都符合CLS,仅有极个别类型的成员不符合CLS,这就保证了所有面向.NET的语言都可以使用框架类库中的类型。
满足CLS就是要求语言特性要一致,那么什么叫做语言特性?这里给出几个具体的语言特性:是否区分大小写,标识符的命名规则如何,可以使用的基本类型有哪些,构造函数的调用方式(是否会调用基类构造函数),支持的访问修饰符等。
那么我们如何检验程序集是否符合CLS呢?.NET为我们提供了一个特性CLSCompliant,便于在编译时检查程序集是否符合CLS。我们来看下面一个例子:
可以注意到,在CLSTest类的前面为程序集加上了一个CLSCompliant特性,表明这个程序集是CLS兼容的。但是,有三处并不满足这个要求,因此编译器给出了警告信息。这三处是:
?不能以大小写来区分成员,因此字段name和方法Name()不符合CLS。
?方法的返回类型和参数类型必须是CLS兼容的,uint和sbyte类型并非CLS兼容,因此GetValue()和SetValue()方法不符合CLS。
?标识符的命名不能以下划线“_”开头,因此属性_MyProperty不符合CLS。
还会注意到,编译器给出的只是警告信息,而非错误信息,因此可以无视编译器的警告,不过这个程序集只能由其他C#语言编写的程序集所使用。
总结
我们对.NET框架的第一感觉就是,.NET框架所提供的庞大类库及编写代码所采用的C#语言等,实际上远不止这些。还包含许多的内容,例如CLI、CIL、CTS、CLS、CLR、JIT、BCL、FCL等,这些内容在《.NET之美》这本书中都进行了深入浅出的讲解,对初学者很实用。如果想真正的理解.NET,仅仅会编码是远远不够得,上面这些东西才是根本。