基元类型
编译器直接支持的数据类型成为基元类型。基元类型和.NET框架类库(FCL)中的类型有直接的映射关系。例如在c#中,基元类型int映射到FCL中就是System.Int32。请看下面的四行代码,他们都能通过编译,并且产生的IL代码都是相同的。
int i = 0;
System.Int32 i = 0;
int i = new int();
System.Int32 i = new System.Int32();
相信的对应关系,大家可以参考MSDN的相关文档。基元类型之间的数据转换可以参考我的上一遍文章,同样存在隐式转换和现实转换,其中的原理都是相同的。当一个值为6.8的Single转型为Int32的数据类型时,一些编译器产生的结果可能是7,而另外的编译器产生的结果则可能是6,特别要指出的是,在c#中总是会舍弃小数点后面的数据。
Checked、UnChecked运算符
很多的时候基元类型的数据运算经常导致数据溢出,很多的时候这种情况是非常危险的,甚至产生非常难以查找的Bug。请看下面的代码:
Byte b = 100;
b = (Byte)(b + 200);
Console.WriteLine(b.ToString());
Console.ReadLine();
输出的结果是大家是意想不到的,44!原因何在?CLR只在32位和64位值上进行算数运算,所以b和200都要首先转换成32的数值,然后进行加法运算,这个结果是个32位的数值,然后转换成Byte类型,这种转换,编译器认为是不安全的,所以就要像上面的代码所显示的,要进行显示转换!这种溢出不是我们所期望的,在程序中我们必须检测异常信息,对溢出进行适当的处理。
C#中的Checked和Unchecked运算符就是处理溢出问题的,并且具有很大的灵活性。我们还是通过下面的代码来分析这个问题。
try
{
Byte b = 100;
//抛出System.OverflowException异常信息
b = checked((Byte)(b + 200));
}
catch (OverflowException ex)
{
//对抛出的异常信息进行处理!
}
在上面的代码中,checked运算符的检测对象是b+200的运算结果能否转换成Byte类型,很明显,这个结果是溢出的,所以程序在运行时将抛出System.OverflowException异常信息。
Byte b = 100;
b = (Byte)checked(b + 200);//不抛出System.OverflowException异常信息
这段代码和上面的代码的不同之处在于,checked运算符的检测对象是不一样的,checked运算符检测的是b+200的结果,很明显,程序不会抛出异常信息。
C#还提供了checked和Unchecked语句用于对整个语句块中的代码进行溢出检查或者不进行溢出检查!请看下面的代码。
checked
{
Byte b = 100;
b = (Byte)(b + 200);
}
由于Checked和UnChecked操作符和语句只影响加,减、乘以及转换IL指令产生的版本,所以在Checked和Unchecked操作符语句内调用一个方法,并不会对该方法内的数据溢出产生影响,这是显而易见的。就像下面的代码一样。原因我在注释中已经写的很清楚了!
checked
{
//假设这个方法的作用是把原来的Byte类型的数加上1000,
//GetSingleMethod()方法是否抛出System.OverflowException
//异常信息取决与其方法的内部实现,而和现有的checked语句无关!
GetSingleMethod(1000);
}
另外还有一个特例,那就是无论事都是用checked和Unchked关键字,在进行System.Decimal类型的数据运算时,如果发出数据溢出,总是会抛出System.OverflowException异常信息!这是因为CLR没有直接操作System.Decimal类型数据的IL指令!由此可见理解CLR对学习.NET的方方面面都起着至关重要的作用!