
2.4 类型转换
在数据类型中曾介绍,"5"、'5'和5是3个不同的数据类型,其中,只有5能参与数据的数学运算。编译器编译程序运行时需要确切地知道数据类型,所以在实际开发中,若需要将"5"和'5'作为整型数据参与运算,则需要将"5"和'5'先改变数据类型,使其变成5,再进行运算。
本节介绍各个数据类型之间的转换,包括基本数据类型间的显式转换和隐式转换、字符串和基本数值类型之间的转换,以及对象类型的转换。
2.4.1 隐式转换和显式转换
由于不同的数据类型有着不同的长度和精度,因此长度和精度较大的数据类型在转换为长度和精度较小的数据类型时,可能存在数据的丢失。如浮点数3.14转换为整型之后是3,其小数点后面的内容将丢失。这种转换是强制性的,是需要显式转换的。
相反,长度和精度较小的数据类型在转换为长度和精度较大的数据类型时,没有数据的丢失,是可以直接转换的,如3转换为浮点数为3.0,数据值与原数据是一样的。在使用时可直接将3作为3.0参与程序中,这种转换称为隐式转换。
1.隐式转换
隐式转换必须是将范围小的类型转换为范围大的类型。如将int类型转换为double、long、decimal或float类型,将long类型转换为float或double类型等。如表2-4所示为隐式类型的转换表。
表2-4 隐式类型转换

在表2-4中,从int、uint、long、ulong到float,以及从long或ulong到double的转换可能会导致精度损失,但是不会影响它的数量级,而且隐式转换不会丢失任何信息。
2.显式转换
显式类型转换也被称作强制类型转换,它需要在代码中明确地声明要转换的类型。显式类型转换可以将取值范围大的类型转换为取值范围小的类型。如表2-5所示列出了需要进行显式类型转换的数据类型。
表2-5 显式类型转换

C#中使用强制类型进行转换时有两种方法:一种是使用括号(),在括号()中给出数据类型标识符(即强制转换的类型),在括号外要紧跟转换的表达式;另外一种是使用Convert关键字进行数据类型的强制转换。
2.4.2 字符串类型转换
显式类型转换和隐式类型转换主要是对数值之间的转换,本节介绍字符串与数值之间的转换。
字符串类型转换为其他类型时有两种方法:一种是使用parse()方法;另外一种是使用Convert类中的方法进行转换。如表2-6所示列出了Convert类的常用转换方法。
表2-6 Convert类的常用转换方法

字符串转换中,最常用的是字符串和数学数据之间的转换。如将字符串转换为能够执行数学运算的数据,参与到数学运算中,如范例3所示。
【范例3】
加号(+)有将数值相加的作用,也有连接字符串的作用。定义字符串类型的两个值“12”和“34”,输出两个变量执行“+”之后的值;将两个变量转换为整型执行“+”运算,输出结果,代码如下。
string num1 = "12"; string num2 = "34"; string strnum = num1 + num2; int intnum = Convert.ToInt32(num1) + Convert.ToInt32(num2); Console.WriteLine("两个字符串的和:{0}", strnum); Console.WriteLine("两个整型数的和:{0}", intnum);
上述代码的执行结果如下所示。
两个字符串的和:1234 两个整型数的和:46
由上述结果可以看出,作为字符串类型时,两个变量的相加结果,相当于将两个字符串中的字符组合在一起,而转换为整型后,其相加结果为数学运算中的相加值。
注意
将字符串转换为其他类型时该字符串必须是数字的有效表示形式。例如,用户可以把字符串“32”转换为int类型,却不能将字符串“name”转换为整数,因为它不是整数有效的形式。
2.4.3 装箱和拆箱
装箱是值类型到Object类型或到此值类型所实现的任何接口类型的隐式转换,用于在垃圾回收堆中存储值类型。
装箱实际上是指将值类型转换为引用类型的过程,装箱的执行过程大致可以分为以下三个阶段。
(1)从托管堆中为新生成的引用对象分配内存。
(2)将值类型的实例字段复制到新分配的内存中。
(3)返回托管堆中新分配对象的地址,该地址就是一个指向对象的引用了。
如下代码演示了如何将int类型的变量val进行装箱操作,然后将装箱后的值进行输出。
int val = 100; object obj = val; //装箱 Console.WriteLine ("对象的值 = {0}", obj); //输出结果
装箱操作生成的是全新的引用对象,这会损耗一部分的时间,因此会造成效率的降低,所以应该尽量避免装箱操作。一般情况下,符合下面的情况时可以执行装箱操作。
(1)调用一个含Object类型的参数方法时,该Object可以支持任意的类型以方便通用,当开发人员需要将一个值类型(如Int32)传入时就需要装箱。
(2)使用一个非泛型的容器,其目的是为了保证能够通用。因此可以将元素类型定义为Object,于是如果要将值类型数据加入容器时需要装箱。
拆箱也叫取消装箱,它是与装箱相反的操作,它是从Object类型到值类型或从接口类型到实现该接口的值类型的显式转换。
拆箱实际上是指从引用类型到值类型的过程,拆箱的执行过程大致可以分为以下两个阶段。
(1)检查对象实例,确保它是给定值类型的一个装箱值。
(2)将该值从实例复制到值类型变量中。
如下示例代码演示了基本的拆箱操作。
int val = 100; object obj = val; //装箱 int num = (int) obj; //拆箱 Console.WriteLine ("num:{0}", num); //输出结果
注意
当一个装箱操作把值类型转换成一个引用类型时,不需要显式地强制类型转换;而拆箱操作把引用类型转换到值类型时,由于它可以强制转换到任何可以相容的值类型,所以必须显式地强制类型转换。