第5章 基元类型、引用类型与值类型 (1)
5.1 基元类型
编译器直接支持的数据类型称为基元类型(primitive type),编译器允许我们用某种简化的语法来操作它们
基元类型和FCL中的类型有直接的映射关系,如C#中把int直接映射为System.Int32类型
C#中有如下一些基元类型:sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, bool, decimal, object, string。我一直都有个疑惑,就是C#中该用string还是String,其实string就是映射了System.String的基元类型,因此二者在使用时是几乎相同的
对基元类型,编译器能识别一些通用的编程模式,并产生必要的IL指令来使代码按期望的方式运行。例如编译器一般会支持和类型转换、文本常量(literals)、操作符相关的一些模式:
1、编译器能在基元类型间进行隐式或显式的转换
2、基元类型还能以文本常量的形式出现,如下代码:
Console.WriteLine(123.ToString() + 456.ToString());
编译时编译器能知道“123”是对应的基元类型如int,然后执行我们想要的操作
3、如果表达式中含有文本常量,编译器能在编译时就计算出结果从而提高代码性能。如 Int32 x = 100 + 20 + 3; 编译后的代码会直接将x设为123而不需要执行时再运算
4、编译器会知道怎样解析出现在代码中的运算符
5.1.1 Checked与Unchecked基元类型操作
不同语言对溢出的处理方式不同。C和C++不把溢出认为是错误,而VB会在检测到整数溢出时抛出一个异常
CLR提供了一个名为add的指令直接做加法运算而不做溢出检查,同时又提供了一个名为add.ovf的指令,它在做加法运算发生溢出时便抛出一个System.OverflowException异常。类似的运算指令还有减法(sub/sub.ovf)、乘法(mul/mul.ovf)以及数据转换(conv/conv.ovf)
C#默认情况下溢出检查是关闭的,编译器中产生的IL指令使用的是不包含溢出检查的版本。可以用/checked+命令行开关来告诉编译器使用带溢出检查的版本。溢出检查将使代码效率有所降低
C#还提供了checked和unchecked操作符以及checked和unchecked语句来进行局部语句的溢出检查设置。由于checked操作符或语句只影响加、减、乘以及转换IL指令产生的版本,在checked操作符或语句内调用一个方法不会对方法造成任何影响
特殊:Decimal
System.Decimal虽然被很多编程语言如C#和VB看作是一个基元类型,但CLR却不是这样,这意味着CLR里没有直接操作Decimal值的IL指令,而是Decimal类型内部自己定义了Add、Subtract、Multiply、Divide等静态方法以及为+、-、*、/等提供了操作符重载方法。于是当我们编译使用Decimal值的代码时,编译器产生的代码实际上会通过调用Decimal类型的成员来执行相关操作,因此操作Decimal的代码效率会比操作其他CLR基元类型的效率要低
由于没有操作Decimal的IL指令,所以checked和unchecked以及相关的编译器命令行开关对它没有任何影响。对Decimal值的操作没有安全地执行时系统总是抛出System.OverflowException异常