5.2 显式类型转换
显式类型转换又叫做显式强制类型转换、强制类型转换,因为不能自动进行转换(和隐式类型转换相比而言),因而需要显式地告知编译器需要类型转换。隐式类型转换往往是由窄向宽的转换,而显式类型转换恰恰相反,是由宽向窄的类型转换。以数值类型为例,从一个取值范围更大的类型向较小的类型转换时,由于可能导致精度损失或引发异常,因此编译器不会自动进行隐式转换,除非明确告知。因此,显式转换也称为收缩转换。
那么,该如何告诉编译器我们确定要做这种显式的转换呢?很简单,只需要在变量前使用一对小括号()运算符,小括号中是目标类型。如果未定义相应的()运算符,则强制转换会失败。以后我们还将学到,还可以使用as运算符进行类型转换,请参阅5.3节,如代码清单5-6所示。
代码清单5-6 long类型到int类型的转换
1 using System;
2
3 namespace ProgrammingCSharp4
4{
5 class TypeConvert
6{
7 public void DoSomething()
8{
9 long longValue=10;
10 int intValue=longValue;
11}
12}
13}
编译上述代码,编译器会产生如下编译错误:
无法将类型"long"隐式转换为"int"。存在一个显式转换(是否缺少强制转换?)
分析一下为什么会产生这样的错误,在代码的第10行,我们试图将取值范围更大的long类型隐式地转换为int类型。前面讲过,这可能会造成信息丢失,因此编译器将之作为一个错误,并拒绝进行转换。如果确实要进行转换,就需要显式类型转换了,即使用()运算符或者as运算符。知道了错误的原因,那么只需对第10行做如下修改即可解决问题:
int intValue=(int)longValue;
这里的()运算符"(int)"明确告知编译器需要将long转换为int。至此,问题解决。
其实,所有的隐式类型转换都可以显式地进行类型转换。因此,可以说隐式类型转换都是隐藏了()运算符的显式类型转换。例如:
int intValue=10;
long longValue=(long)intValue;//等价于long longValue=intValue;
接下来,将分别研究数值类型、引用类型的显式类型转换,以及拆箱转换和显式类型转换的关系。
5.2.1 数值类型
在下列情况下,由于不存在自动的隐式转换,因此必须明确地进行显式类型转换:
❑sbyte到byte、ushort、uint、ulong、char
❑byte到sbyte、char
❑short到sbyte、byte、ushort、uint、ulong、char
❑ushort到sbyte、byte、short、char
❑int到sbyte、byte、short、ushort、uint、ulong、char
❑uint到sbyte、byte、short、ushort、int、char
❑long到sbyte、byte、short、ushort、int、uint、ulong、char
❑ulong到sbyte、byte、short、ushort、int、uint、long、char
❑char到sbyte、byte、short
❑float到sbyte、byte、short、ushort、int、uint、long、ulong、char、decimal
❑double到sbyte、byte、short、ushort、int、uint、long、ulong、char、float、decimal
❑decimal到sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double
我们知道,隐式类型转换可以看作省略了()运算符的显式类型转换,因此对于数值类型间的转换来说,总是使用()运算符也没问题。
但是,显式的数值类型转换有可能造成信息丢失或者导致系统抛出异常,这也是系统为什么对于这种类型转换要求人工干预并且特别确认的原因。