更新:2007 年 11 月
错误消息
无法将类型“type”隐式转换为“type”编译器要求显式转换。例如,可能需要将右值转换成与左值相同的类型。或者必须提供转换例程以支持某些运算符重载。
在将某个类型的变量赋给其他类型的变量时必须进行转换。当在不同类型的变量之间进行赋值时,编译器必须将赋值运算符右边的类型转换为该赋值运算符左边的类型。假设有下面的代码:
复制代码 | |
---|---|
int i = 50; long lng = 100; i = lng; |
i = lng; 进行赋值运算,但赋值运算符左右两边变量的数据类型不匹配。进行赋值前,编译器将变量 lng(类型为 long)隐式转换为 int。此为隐式转换,原因是没有代码显式指示编译器执行此转换。此代码的问题在于上述转换被视为收缩转换,而编译器不允许进行隐式收缩转换,原因是可能会丢失数据。
如果转换后的数据类型所占用的内存存储空间比转换前的数据类型所占用的少,则存在收缩转换。例如,将 long 类型转换为 int 类型就被视为收缩转换。long 类型占用 8 个字节的内存,而 int 类型只占用 4 个字节。若要查看数据丢失如何发生,请考虑以下示例:
复制代码 | |
---|---|
int i = 50; long lng = 3147483647; i = lng; |
变量 lng 现在包含的值无法存储在变量 i 中,原因是该值太大。如果要将该值转换为 int 类型,就会丢失一些数据,并且转换后的值不同于转换前的值。
扩大转换与收缩转换相反。对于扩大转换,转换后的数据类型占用的内存存储空间比转换前的数据类型占用的多。下面是一个扩大转换的示例:
复制代码 | |
---|---|
int i = 50; long lng = 100; lng = i; |
请注意此代码示例和第一个示例之间的区别。这里,变量 lng 位于赋值运算符的左边,所以它是赋值的目标。在可以进行赋值前,编译器必须将变量 i(类型为 int)隐式转换为 long 类型,这是一个扩大转换,原因是从占用 4 个字节内存的类型 (int) 转换为占用 8 个字节内存的类型 (long)。由于不会发生数据丢失,所以允许进行隐式扩大转换。任何可以用 int 类型存储的值也可以用 long 类型存储。
我们知道隐式收缩转换是不允许的,因此为了能够编译这些代码,就需要显式转换数据类型。显式转换是使用强制转换来完成的。强制转换是 C# 中用来描述将一种数据类型转换为另一种数据类型的术语。若要编译这些代码,我们需要使用以下语法:
复制代码 | |
---|---|
int i = 50; long lng = 100; i = (int) lng; // cast to int |
第三行代码通知编译器在进行赋值前,将变量 lng(类型为 long)显式转换为 int 类型。切记,使用收缩转换可能会丢失数据。使用收缩转换时应小心,而且即使可以编译代码,也可能会在运行时获得意外的结果。
此讨论只针对值类型。使用值类型就是直接使用存储在变量中的数据。但 .NET Framework 还具有引用类型。使用引用类型就是使用对变量的引用,而不是使用实际数据。引用类型的示例是类、接口和数组。不能隐式或显式地将一个引用类型转换为其他引用类型,除非编译器允许特定的转换或可以实现相应的转换运算符。
下面的示例生成 CS0029:
复制代码 | |
---|---|
// CS0029.cs public class MyInt { private int x = 0; // Uncomment this conversion routine to resolve CS0029 /* public static implicit operator int(MyInt i) { return i.x; } */ public static void Main() { MyInt myInt = new MyInt(); int i = myInt; // CS0029 } } |