标签:
我们知道,无论什么类型,所有的数据都是一系类的位,即0和1。变量的含义是通过解释这些数据的方式来传递的。最简单的类型的示例是Char类型,这种类型用一个数字表示Unicode字符集中的一个字符。实际上,这个数字与ushort是存储方式完全相同——它们都存储0-65535之间的数字。
但一般的情况下,不同类型的变量使用不同的模式来表示数据,这意味着,即使可以把一系类的位从一种从一种类型的变量移动到另一种类型变量中(或许它们占用的存储空间相同,或许目标类型有足够的存储空间包含所有的源数据位),结果也可能与期望不同。
这并不是数据位从一个变量到另一个变量的一对一映射,而是需要对数据进行类型转换。类型转换采用以下两种方式。
隐式转换:从类型A到类型B的转换可以在所有情况下进行,执行转换的规则非常简单,可以让编译 器执行转换。
隐式转换:从类型A到类型B的转换只能在某些情况下进行,转换的规则比较复杂,应进行某种类型的处理。
隐式转换不需要做任何工作,也不需要另外编写代码。考虑下面的代码:
Var1=Var2;
如果Var2的类型可以隐式的转换为Var1的类型,这个赋值语句就涉及一个隐式转换。它也可能只处理相同类型的两个变量,不需要隐式转换。例如,unshort和char的值是可以互换的,因为它们都可以存储0-65535之间的数字,在这两个类型之间可以进行隐式转换。
任何A类,只要其取值范围完全包含在类型B的取值范围内,就可以隐式转换为类型B。原因是,如果要把一个值放在变量中,而该值超出了变量的取值范围,就会出问题。
例如,short类型的变量可以存储0-32767的数字,而byte可以存储的最大值为255,所以如果要把一个short值转换为byte值,就会出问题。如果short包含的值在256-32767之间,相应的数值就不能放在byte中。
但是如果short类型变量中的值小于255,就应能转换这个值,事实上是可行的。但是不能使用隐式转换,而必须使用显示转换。
顾名思义,在明确要求编译器把数值从一种数据类型转换为另一种数据类型时,就是在执行显示转换。因此这需要另外编写代码,代码的格式将随着转换方法而异。在学习显示转换代码前,先分析如果不添加任何显示转换代码,会发生什么。
byte destinationVar; short sourceVar=7; destinationVar=sourceVar; Console.WriteLine("sourceVar val:{0}",sourceVar); Console.WriteLine("destinationVar val:{0}",destinationVar);
如果编译这段代码,就会产生如下错误:
错误 1 无法将类型“short”隐式转换为“byte”。存在一个显式转换(是否缺少强制转换?)
为了成功编译这段代码,我们需要添加用于强制转换的代码,强制转换就是强数据从一种类型转换为另一种类型,其语法为:
<(A type)B> , 在这里就是<(destinationType)sourceVar>即(byte)sourceVar。
byte destinationVar; short sourceVar = 7; destinationVar = (byte)sourceVar; Console.WriteLine("sourceVar val:{0}", sourceVar); Console.WriteLine("destinationVar val:{0}", destinationVar);
这只是在某些情况下是可行的,彼此之间几乎没有什么关系的类型或根本没有关系的类型不能进行强制转换。
在试图把一个值转换为不合适的变量时,可能会导致数据丢失,如下所示:
byte destinationVar; short sourceVar = 281; destinationVar = (byte)sourceVar; Console.WriteLine("sourceVar val:{0}", sourceVar); Console.WriteLine("destinationVar val:{0}", destinationVar); Console.ReadKey();
结果如下:
sourceVar val:281 destinationVar val:25
发生了什么?看看这两个数字的二进制表示,以及可以存储在byte中的最大值255:
281=100011001 025=000011001 255=011111111
可以看到,元数据的最左边一位丢失了。这会引发一个问题:数据如何丢失的?显然,当要显示地把一种数据类型转换为另一种数据类型时,最好能够了解是否有数据丢失了。如果不知道这些,就会发生严重的问题。
一种方式是简单地检查原变量的值,把它与目标变量的取值范围进行比较。还有另一个技术,迫使系统特别注意运行期间的转换。在将一个值放在一个变量中时,如果该值过大,不能放在该类型的变量中,就会导致溢出,这就需要检查。
这里要用到两个关键字checked 和unchecked,称为表达式的溢出检查上下文。以下述方式使用这两个关键字:
checked(expression) unchecked(expression)
下面对上一个示例进行溢出检查:
byte destinationVar; short sourceVar = 281; destinationVar = checked((byte)sourceVar); Console.WriteLine("sourceVar val:{0}", sourceVar); Console.WriteLine("destinationVar val:{0}", destinationVar); Console.ReadKey();
在执行这段代码时,程序会抛出异常,这里会抛出“’System.OverflowException‘类型的未经处理的异常”。
但是,在这段代码中,如果用unchecked代替checked,就会得到与之前一样的结果。
另一种方式是,配置应用程序,让这种类型的表达式都包含checked关键字,除非表达式明确使用unchecked关键字(换言之,可以改变溢出检查的默认设置)。为此,应修改项目的属性,在VS中右击解决方案窗口中的项目,选择属性选项。单击窗口左边的生成,打开生成设置,点击高级,选中“检查运算上溢/下溢”。
为了成功的执行此类转换,所提供的字符串必须是数值的有效表达方式,该数还必须是不会溢出的数。数值的有效表达方式是:首先是一个可选符号(加号或减号),然后是0为或多位数字,一个据点后跟一位或多位数字,接着是一个可选的e或E,后跟一个可选符号和一位或多位数字(在这个序列之前或之后)和空格。利用这些可选的额外数据,就可以看出-1.2451e-24这样复杂的字符串是一个数值。
按这种方式可以进行许多显示转换,如 Convert.ToBoolean(val)、Convert.ToString(val)、Convert.ToInt32(val)等。
其中val可以是大多数变量类型(如果这些命令不能处理该类型的变量,编译器就会告诉用户)。转换的名称略不同于C#类型名称,例如,要转换为int,应使用Convert.ToInt32()。这是因为这些命令来自于.NET Framework的System名称空间。而不是本机C#本身。这样它们就可以在除C#以外的其他.NET兼容语言中使用。
对于这些转换要注意的一个问题是:它们总是要进行溢出检查,checked和unchecked关键字以及项目属性设置不起作用。
标签:
原文地址:http://www.cnblogs.com/haizhibin1989/p/4672271.html