wiki.php 用Markdown写wiki是一种什么样的体验?

IL:CS与Vb.NET的数据转换为什么不同?.md

最后更新于 2019-10-06 15:00:40

用惯了Vb的程序员,在对Integer到UInteger进行数据转换的时候,一定会知道要加个Try或者进行数值检测,否则就会引发一个该死的数值溢出错误。
然而,在C#中,将int转换为uint,却不会引发任何的错误,这是为什么呢?

C#:

int i = -1;
uint ui = (uint)i; //此刻ui的值等于 uint.MaxValue

Vb.NEt:

Dim i As Integer = -1
Dim ui As Integer = i '错误,数值溢出

这到底是怎么回事?同是.NET语言,怎么差距就这么大来?!
既然想破脑袋想不通,只有反汇编译IL,查看原始的汇编代码。

C#:

ldc.i4.m1 //将 -1 压栈
stloc.0 //存储临时变量0
ldloc.0 //加载变量0
stloc.1 //存入变量1

VB:

ldc.i4.m1
stloc.0
ldloc.0
conv.ovf.u4 //此步关键,执行溢出检测
stloc.1

可以看出来,VB所生成的代码,仅仅比C#多了一个conv指令,它执行转换并进行溢出检测,如发生溢出时引发OverflowException异常。当然,它更强调了转换的安全性,但是当我们需要执行更高级的位运算转换时,这就显得极不方便了。
解决方法有二,一是在编译器参数中添加 /removeintchecks+ 命令,二是在[项目属性面板-编译-高级编译选项]中选择[不做整数溢出检查]。
当然,默认情况下还是使用整数溢出检查比较好。

最后再来补充一下如何在C#中进行溢出检测,一是和上面的方法一样在编译设置中添加整数溢出检测;另一个更方便,是在代码中添加一个 checked 块:

int i = -1;
uint ui = checked( (uint)i );

下面的格式也可以:

checked {
int i = -1;
uint ui = (uint)i;
}

PS:为什么C#就是比VB方便啊?! >_<