数字的转换
任何数字类型都可以转换为其他数字类型,如图17-8所示。一些转换是隐式的,而另外一
些转换则必须是显式的。
隐式数字转换
图17-9展示了隐式数字转换。
- 如果沿着箭头存在一条从源类型到目标类型的路径,则存在从源类型到目标类型的隐式
转换。 - 沿着箭头不存在从源类型到目标类型的路径的数字转换一定是显式转换。
图中所演示的,正如我们期望的那样,占据较少位的数字类型可以隐式转换为占据较多位的
数字类型。
溢出检测上下文
我们已经知道了,显式转换可能会丢失数据并且不能在目标类型中同等地表示源值。对于整
数类型,允许我们选择运行时是否应该在进行类型转换时检测结果溢出。这将通过checked运
算符和checked语句来实现。
- 代码片段是否被检查称作溢出检测上下文。
- 如果我们指定一个表达式或一段代码为checked,CLR会在转换产生溢出时抛出一个
0verflowException异常。 - 如果代码不是checked,转换会继续而不管是否产生溢出。
- 如果我们指定一个表达式或一段代码为checked,CLR会在转换产生溢出时抛出一个
- 默认的溢出检测上下文是不检查。
checked和unchecked运算符
checked和unchecked运算符控制表达式的溢出检测上下文。表达式放置在一对圆括号内并
且不能是一个方法。语法如下所示:
checked(表达式)
unchecked(表达式)
例如,如下代码执行了相同的转换——第一个在checked运算符内,而第二个在unchecked运算符内。
- 在上下文中,会忽略溢出,结果值是208。
- 在checked上下文中,抛出了0verflowException异常。
ushort sh=2000;
byte sb;
sb=unchecked((byte)sh); //大多数重要的位丢失
Console.WriteLine($"sb:{sb}");
sb=checked((byte)sh); //抛出OverflowException异常
Console.WriteLine($"sb:{sb}");
这段代码产生了如下的输出:
sb:208
Unhandled Exception:System.OverflowException:Arithmetic operation resulted in an overflow.at
Test1.Test.Main() in C:\Programs\Test1\Program.cs:line 21
checked语句和unchecked语句
checked和unchecked运算符用于圆括号内的单个表达式。而checked和unchecked语句执行
相同的功能,但控制的是一块代码中的所有转换,而不是单个表达式。
checked语句和unchecked语句可以被嵌套在任意层次。例如,如下代码使用了checked语句
和unchecked语句,并产生了与之前使用checked和unchecked表达式的示例相同的结果。然而,
在这种情况下,影响的是一段代码,而不仅仅是一个表达式。
byte sb;
ushort sh=2000;
checked
{
unchecked
{
sb=(byte)sh;
Console.WriteLine($"sb:{sb}");
}
sb=checked((byte)sh);
Console.WriteLine($"sb:{sb}");
}
显式数字转换
我们已经知道了,隐式转换之所以能自动从源表达式转换到目标类型是因为不可能丢失数
据。然而,对于显式转换而言,就可能丢失数据。因此,作为一名程序员,知道发生数据丢失时
转换会如何处理很重要。
在本节中,我们来看看各种显式数字转换。图17-10演示了图17-8中显式转换的子集。
整数类型到整数类型
图17-11演示了整数到整数的显式转换的行为。在checked的情况下,如果转换会丢失数据,
操作会抛出一个0verflowException异常。在unchecked的情况下,丢失的位不会发出警告。
float或double转到整数类型
当把浮点类型转换为整数类型时,值会舍掉小数,截断为最接近的整数。图17-12演示了转
换条件。如果截断后的值不在目标类型的范围内:
- 如果溢出检测上下文是checked,则CLR会抛出0verf10wException异常,
- 如果上下文是unchecked,则c#将不定义它的值应该是什么。
decimal到整数类型
当从decimal转换到整数类型时,如果结果值不在目标类型的范围内,则CLR会抛出Overflow一
Exception。图17-13演示了转化条件。
double到float
float类型的值占32位,而double类型的值占64位。当double被舍入为float时,double
类型的值被舍人到最接近的float类型的值。图17-14演示了转换条件。
- 如果值太小而不能用float表示,那么值会被设置为正0或负0。
- 如果值太大而不能用float表示,那么值会被设置为正无穷大或负无穷大。
float或double到decimal
图17–15演示了从float类型到decimal类型的转换条件。
- 如果值太小而不能用decimal类型表示,那么值会被设置为0。
- 如果值太大,那么CLR会抛出0verflowException异常。
图17–15演示了从float类型到decimal类型的转换条件。 - 如果值太小而不能用decimal类型表示,那么值会被设置为0。
= 如果值太大,那么CLR会抛出0verflowException异常。
decimal到float或double
从decimal类型转换到float类型总是会成功。然而,这可能会损失
转换条件。