略讲类型转换

来源:互联网 发布:中国言论自由知乎 编辑:程序博客网 时间:2024/05/22 13:10

一些常见的问题:

1.      为什么C#不能讲字符串直接强制转换为int,而是额外提供一个System.Convert.ToInt32()方法。

2.      几种常见转换之间的性能对比。

1.      关于溢出,如何检查溢出。

 

1.基元类型之间的类型转换。

需要注意的是,基元类型之间的转换是不会抛出异常的,这一点很重要,譬如int可以转换为byte(溢出也算)而不会抛出任何异常,当然你可能会说,这可能会产生溢出!是的,当int大于256时,确实会产生溢出,但是这里是从计算机位级考虑数据转换的,所以这里溢出也是正确的。

IL中有一些列转换指令可以进行基元类型之间的转换,这些指令不会抛出任何异常。譬如conv.i1可以将一个其他值转换为byte。譬如下面这段代码就会使用这个指令:

byte c=(byet)0x12345;

c最终是什么呢?可以输出一下试试。

默认情况下,上述代码是不会抛出异常的,这是因为编译器默认生成了conv.i1指令,而conv.i1指令在发生溢出时是不会抛出任何异常的,如果想要在发生溢出时得到一个通知,可以使用conv.i1,这条指令在溢出时会抛出一个OverflowException异常。

要想要上述代码抛出异常,如下所示:

Checked

{

    Byte c=(byte)0x12345;

}

这时候会抛出一个OverflowException异常,这在调试的时候非常有用。

 

关于这方面的内容,请见如下博客:http://blog.csdn.net/dingxiang506/article/details/8639033

注意:位级别转换就是在转换的过程中位模式不变,只是进行相应的符号扩展(在前面填充0或者1),或者直接截断处理。将byte类型的256转换为int类型还是256他们的位模式从

1111 1111到1111 11111111 1111 1111 1111 1111 1111。也就是将1111 1111前面所有位都符号扩展到1.

 

2.   引用类型之间的类型转换

上面所说的是基元类型之间的转换,他们之间的转换都是从位级考虑的。对于引用类型之间的转换则不同。

引用类型之间的转换最终会转换到IL的castclass指令。这条之间可以将一个引用类型转换为另一个引用类型,前提是二者必须具有继承关系,如果二者没有继承关系,那么就会抛出一个InvalidCastException异常。

可以看到,虽然在C#中,对于基元类型和引用该类型之间的的强制类型转换,都是通过强制类型转换符(也就是那个括号)来实现的,但是在不同的语义下会产生不同的指令。对于机缘类型的类型转换会产生上面所说的指令,对于引用类型之间的转换会产生castclass指令。

如果不想再转换的过程中跑出一个异常,那么就可以使用is和as操作符。

3.   拆箱和装箱

拆箱和装箱也可以算是一种类型转换吧!毕竟从值类型和引用类型是两种不同的类型。这里不打算讲解装箱和拆箱的细节问题,而是讨论转换过程中可能会出现的异常,从而不至于在运行时抛出异常时而不知所措。

在C#中,对于装箱而言,是不会抛出任何异常的,因为编译器限制了装箱的条件:要想将一个值类型装箱成引用类型,这个值类型必须是引用类型的派生类。所以这里,装箱是不会产生任何异常的。

但是,在拆箱的过程中则不然,拆箱可能会出现令人讨厌的InvalidCastException异常。如果将一个int装箱之后,拆箱成一个byte就会抛出那个异常。请看如下代码:

  int i=12;

            objecta = i;

            byteb = (byte)a;

毫无疑问,这段代码在运行的时候会抛出一个InvalidException异常。Int装箱之后会在堆中创建一个对象,这个对象的值也是12。然后我们做的是将这个堆中的对象拆箱成byte,CLR认为这是一个错误,他会抛出InvalidException异常,来阻止我们这么做。

当然了,如果我们就是想将a拆箱成byte,怎么做呢?要想达到这种效果可以就代码进行入下修该:

  int i=12;

            objecta = i;

            byteb = (byte)(int))a;

现在编译运行,正常。

注:将一个int类型进行装修的时候,会在堆中创建一个对象,这个对象不仅包含原来值的一个副本,还包含一个类型信息。就那上面的例子,12装箱会在堆中产生一个对象,这个对象的值是12,除此之外,这个对象还包含一个记录,来指定这是一个int类型。拆箱的时候,会检查这个记录和目标类型时否匹配,如果不匹配,就会抛出一个InvalidCastException异常

4.   特殊的类型转换

严格的说,这里并不是类型转换,但是他们达到了类型转换的效果,所以称他们为特殊的类型转换。

Object的ToString方法。

Convert的一些列Toxxxx方法。

有时候,用户在界面中输入了一个字符串12,然后我们想要将其转换为整数类型,从而执行基本算术运算。想要将一个字符串转换为一个int,用普通做法是做不到的。你不能直接将字符串12转换为整数12,编译器不让你做,如下:

String  input=“12“;

Int  age=(string)input;

如果写出如上代码,编译器肯定不让过。因为input和age具有不同的位级表示:

Input位级表示:

age的位级表示:

如果将input转换为age,将转换成了什么?从位级角度看,这完全没有任何意义。显然普通的做法是无法将string转换为int的。

C#中提供了Convert.ToInt32(string input)方法,该方法可以分析参数input,发现里面存储的是49,50(UTF8编码),并将49,50映射到整数12,然后将返回整数12.

 

原创粉丝点击