• .NET 基础架构概念
• 类型基础
• 通用类型系统
• CLI、CTS、CLS的关系简述
1. 引言
本文不是连环画,之所以在开篇以图形的形式来展示本文主题,其实就是想更加特别的强调这几个概念的重要性和关注度,同时希望从剖析其关系和联系的角度来讲述.NET Framework背后的故事。因为,在作者看来想要深入的了解.NET,必须首先从了解类型开始,因为CLR技术就是基于类型而展开的。而了解类型则有必要把焦点放在.NET类型体系的公共基础架构上,这就是:通用类型系统(Common Type System, CTS)。
我之所以将最基本的内容以独立的章节来大加笔墨,除了为后面几篇关于对类型这一话题深入讨论做以铺垫之外,更重要的是从论坛上、博客间,我发现有很多同行对.NET Framework基础架构的几个重要体系的理解有所偏差,因此很有必要补上这一课,必备我们在深入探索知识的过程中,能够游刃有余。
2. 基本概念
还是老套路,首先引入MSDN对通用类型系统的定义,通用类型系统定义了如何在运行库中声明、使用和管理类型,同时也是运行库支持跨语言集成的一个重要组成部分。通用类型系统执行以下功能:
• 建立一个支持跨语言集成、类型安全和高性能代码执行的框架。
• 提供一个支持完整实现多种编程语言的面向对象的模型。
• 定义各语言必须遵守的规则,有助于确保用不同语言编写的对象能够交互作用。
那么我们如何来理解呢?
还是一个现实的场景来引入讨论吧。小王以前是个VB迷,写了一堆的VB.NET代码,现在他变心了,就投靠C#的阵营,因为流行嘛。所以当然就想在当前的基于C#开发的项目中,应用原来VB.NET现成的东西,省点事儿:-)。那么CLR是如何来实现类型的转换的,例如Dim i as Single变量i,编译器会自动的实现将i由Single到float的映射,当然其原因是所有的.NET编译器都是基于CLS实现的。具体的过程为:CTS定义了在MSIL中使用的预定义数据类型,.NET语言最终都要编译为IL代码,也就是所有的类型最终都要基于这些预定义的类型,例如应用ILDasm.exe分析可知,VB.NET中Single类型映射为IL类型就是float32,而C#中float类型也映射为float32,由此就可以建立起VB.NET和C#的类型关系,为互操作打下基础。
Code
.method public hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// 代码大小 15 (0xf)
.maxstack 1
.locals init (float32 V_0)
IL_0000: nop
IL_0001: ldc.r4 1.
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: call void [mscorlib]System.Console::WriteLine(float32)
IL_000d: nop
IL_000e: ret
} // end of method BaseCts::Main
过去,由于各个语言在类型定义方面的不一致,造成跨语言编程实现的难度,基于这一问题,.NET中引入CTS来解决各个编程语言类型不一致的问题,类型机制使得多语言的代码可以无缝集成。因此CTS也成为.NET跨语言编程的基础规范,为多语言的互操作提供了便捷之道。可以简单的说,基于.NET的语言共同使用一个类型系统,这就是CTS。
进一步的探讨通用类型系统的内容,我们知道CTS支持两种基本的类型,每种类型又可以细分出其下级子类,可以以下图来表示:
.NET提供了丰富的类型层次结构,从上图中也可以看出该层次结构是基于单继承层次实现的,反映了.NET面向对象原则中实现单继承、接口多继承的特点。关于值类型和引用类型,是之后要探讨的重点内容,也是『品味类型』子系列的重中之重,在此不作进一步探讨,但是上面的这张图有必要清楚的印在心中,因为没有什么比这个更基础的了。
3. 位置与关系
位置强调的是CTS在.NET技术框架中的位置和作用,作者期望以这种方式来自然的引出.NET技术架构的其他基本内容,从而在各个技术要点的层次中,来讲明白各个技术要点的些细联系,从大局的角度来对其有个基本的把握。我想,这样也可以更好的理解CTS本身,因为技术从来都不是孤立存在的。
.NET技术可以以规范和实现两部分来划分,而我们经常强调和提起的.NET Framwork,主要包括公共语言运行时(Common Language Runtime, CLR)和.NET框架类库(Framework Class Library, FCL),其实是对.NET规范的实现。而另外一部分:规范,我们称之为公共语言架构(Common Language Infrastructure, CLI),主要包括通用类型系统(CTS),公共语言规范(Common Language Specification, CLS)和通用中间语言(Common Intermediate Language, CIL)。我们以图的形式来看看CTS在.NET技术阵营中的位置,再来简要的介绍新登场的各个明星。
• CLI,.NET技术规范,已经得到ECMA(欧洲计算机制造商协会)组织的批准实现了标注化。
• CTS,本文主题,此不冗述。
• CLS,定义了CTS的子集,开发基于CTS的编译器,则必须遵守CLS规则,由本文开头的图中就可以看出CLS是面向.NET的开发语言必须支持的最小集合。
• CIL,是一种基于堆栈的语言,是任何.NET语言编译产生的中间代码,我们可以理解为IL就是CLR的汇编语言。IL定义了一套与处理器无关的虚拟指令集,与CLR/CTS的规则进行映射,执行IL都会翻译为本地机器语言来执行。常见的指令有:add, box, call, newobj, unbox。另外,IL很类似于Java世界里的字节码(Bytecode),当然也完全不是一回事,最主要的区别是IL是即时编译(Just in time, JIT)方式,而Bytecode是解释性编译,显然效率上更胜一踌。
• CLR,.NET框架核心,也是本系列的核心。类似于Java世界的JVM,主要的功能是:管理代码执行,提供CTS和基础性服务。对CLR的探讨,将伴随着这个系列的成长来慢慢展开,在此就不多说了。
• FCL,提供了一整套的标准类型,以命名空间组织成树状形式,树的根是System。对程序设计人员来说,学习和熟悉FCL是突破设计水平的必经之路,因为其中数以万计的类帮助我们完成了程序设计绝大部分的基础性工作,重要的是我们要知道如何去使用。
可见,这些基本内容相互联系,以简单的笔墨来澄清其概念、联系和功能,显然还不够力度。然而在此我们以抛砖引玉的方式来引入对这些知识的探求,目的是给一个入口,从此来进行更深入的探索是每个设计人员的成长的关键,就像对FCL的认识,需要实践,需要时间,需要心思。
4. 通用规则
• .NET中,所有的类型都继承自System.Object类。
• 类型转换,通常有is和as两种方式,具体的探讨可以参考我的另一拙作《第一回:恩怨情仇:is和as》。另外,还有另外的几个类型转换的方式:(typename)valuename,是通用方法;Convert类提供了灵活的类型转换封装;Parse方法,适用于向数字类型的转换。
• 可以给类型创建别名,例如,using mynet = Anytao.net.MyClass,其好处是当需要有两个命名空间的同名类型时,可以清楚的做以区别,例如:
Code
using AClass = Anytao.net.MyClass;
using BClass = Anytao.com.MyClass;
其实,我们常用的int、char、string对应的是System.Int32、System.Char、System.String的别名。
• 一个对象获得类型的办法是:obj.GetType()。
• Typeof操作符,则常在反射时,获得自定义类型的Type对象,从而获取关于该类型的方法、属性等。
• 可以使用 CLSCompliantAttribute 将程序集、模块、类型和成员标记为符合 CLS 或不符合 CLS。
• IL中使用/checked+开关来进行基元类型的溢出检查,在C#中实现这一功能的是checked和unchecked操作符。
• 命名空间是从功能角度对类型的划分,是一组类型在逻辑上的集合。
5. 结论
类型的话题,是个老掉牙的囫囵觉,但也是个永不言退的革命党。在实际的程序设计中,我们经常要吃这一亏。因为,很多异常的产生,很多性能的损耗,很多冗余的设计都和类型解下不解之缘,所以清晰、清楚的了解类型,没有什么不可以。重要的是,我们以什么角度来了解和化解,内功的修炼还是要从内力开始。本系列不求包罗万象,但求以更新鲜、更全面的角度,清楚、干净、深入的把某个问题说透,此足尹。
品味类型,就从CTS开始了。