一、.NET源代码编译过程
由于Microsoft 在 .NET 平台上提供 3 种语言 – C#、F# 和 Visual Basic,所以, .NET被设计成本质上并不知道所运行的程序代码到底是哪种语言,因为.NET只认识IL语言。IL语言即 Intermediate Language (微软中间语言)。为了说清楚整个事件的来龙去脉,我们以C#源代码为例。
首先,程序员利用Visual Studio开发C#的源代码,然后语言编译器(Language Compiler)将源代码编译为IL中间语言,实际上是一些元数据和中间语言指令,接着在运行这个IL程序时,JIT编译器将根据系统环境将IL中间语言指令转换为机器码。
这里面有一个疑问,为什么不一开始就直接编译成机器码,而是编译成IL中间码?
JIT的全名叫即时编译器,它是在运行时环境中发生的编译行为。不同的CPU或操作系统的环境是不同的,为了实际跨平台运行C#程序,所以只能一开始将源代码编译成IL中间码,等到实际运行时,再根据当前的CPU或操作系统环境将IL中间码由JIT编译成机器代码。
所以,对于.NET的CLR运行时而言,它只认识IL中间码,不在乎这个中间码是C#编译而来,还是由VB编译而来。正是因为 C#、F# 和 Visual Basic都可以开发.NET应用程序,.NET 为了能与多种编程语言代码进行交互,于是它制定了一个通用类型系统 (common type system,CTS),要求所有语言都必须遵守这个约束。
二、通用类型系统 (CTS)
请注意,CTS是一个非常重要的知识点,程序员一定要理解它存在的必要,以及它的职责范围。因为程序员在本质上是申请内存,操作内存数据,归还内存的过程。要申请多大的内存,这个就要看CTS的脸色。CTS将内存分成多种类型,为了节约内存资源,有短一点的只占一个字节长度的内存,也有稍长一点的占4个字节的内存,或者8个字节的内存等等。还是那句话,按需申请。
CTS要面临可能来自C#、F#或VB语言的内存申请要求,所以为了方便统一管理,于是提供了一系列标准的基元类型(Primitive Type),不管是C#程序员,还是VB程序员,在申请内存时,都得按这个基元类型表进行申请。我的地盘我说了算!
除此之外,CTS还拥有其它的功能:
- 建立用于跨语言执行的框架。
- 提供面向对象的模型,支持在 .NET 实现上实现各种语言。
- 定义处理类型时所有语言都必须遵守的一组规则。
- 提供包含应用程序开发中使用的基本基元数据类型(如
Boolean
、Byte
、Char
等)的库。
在本节课程中,我们先了解一下CTS提供了哪些基本基元类型(Primitive Type)。因为除了Boolean
、Byte
、Char
属于基元类型,像类、结构、枚举这些也是基元类型,但它们不算基本基元类型。
重庆教主友情提示
其实,我们学习C#语言这门课程时,大多数时候都是在学习CTS的基元类型
三、基本基元类型(Primitive Type)
编译器直接支持的数据类型称为基元类型(primitive type)。基本的基元类型如下表所示:
基元类型名称 | 说明 | 范围 |
System.SByte | 有符号8位值 | |
System.Byte | 无符号8位值 | |
System.Int16 | 有符号16位值 | |
System.UInt16 | 无符号16位值 | |
System.Int32 | 有符号32位值 | |
System.UInt32 | 无符号32位值 | |
System.Int64 | 有符号64位值 | |
System.UInt64 | 无符号64位值 | |
System.Char | 16位Unicode字符 | |
System.Single | IEEE32位浮点值 | |
System.Double | IEEE64位浮点值 | |
System.Boolean | true/false值 | |
System.Decimal | 128位高精度浮点值,常用于不容许舍入误差的金融计算 | |
System.String | 字符数组 | |
System.Object | 所有类型的基类型 |
这些基元类型都定义在System命名空间当中,如果要使用其中的基元类型,则必须指明它的命名空间或者通过using将System命名空间引入到源文件的开头。
虽然.NET提供了这些基元类型,但是,C#、F#、VB也拥有属于自己的基础数据类型,以及声明这些基础数据类型的关键字。比如,在C#中我们用string定义一个字符串,在.NET中用String定义一个字符串,所以C#的基础数据类型基本上与.NET的基础基元类型有着一一对应的关系。
我们在下一节来介绍两者的对比关系。
——重庆教主 2023年12月19日