implicitly convert type 'int' to 'short'的原因与解决方法

所属分类: 网络编程 / ASP.NET 阅读数: 509
收藏 0 赞 0 分享
看看下面的代码:
复制代码 代码如下:

sbyte sba, sbb,sbv;
sba = 1;
sbb = 2;
sbv = sba + sbb;

byte ba, bb, bv;
ba = 1;
bb = 2;
bv = ba + bb;

short sa, sb, sv;
sa = 1;
sb = 2;
sv = sa + sb;

ushort usa, usb, usv;
usa = 1;
usb = 2;
usv = usa + usb;

你觉得这段代码能否正确执行?结果会怎样? 结果就是:这段代码会出现编译错误.
正确的代码应该如下:
复制代码 代码如下:

sbyte sba, sbb,sbv;
sba = 1;
sbb = 2;
sbv = (sbyte)(sba + sbb);

byte ba, bb, bv;
ba = 1;
bb = 2;
bv = (byte)(ba + bb);

short sa, sb, sv;
sa = 1;
sb = 2;
sv = (short)(sa + sb);

ushort usa, usb, usv;
usa = 1;
usb = 2;
usv = (ushort)(usa + usb);

MessageBox.Show(string.Format("{0},{1},{2},{3}", sbv, bv, sv, usv));

这是什么原因呢? 
       其实CLR底层只支持 int,int64,native int, float , double几种数据类型. 像上面的sbyte,byte,short,ushort, clr底层是不支持的,在底层这些类型是用int表示的. CLR的堆栈中压入的数字,最小是4字节,小于4字节的会根据其类型进行符号扩展或者0扩展为4字节int型. 这样四则运算的结果也是int型,最后再赋值需要进行强制类型转换. 分析一下编译后的IL代码就清楚了.

下面这个代码为什么能编译呢?
复制代码 代码如下:

short sb;
sb=2;
sb += 1;

其实编译后的IL代码中最后赋值也包含了类型转换操作.

看下更加详细的解释:

复制代码 代码如下:

short s=0;
s = s + 1; //报错,右端是复杂表达式,1被解释成int
s+=1; //不报错,1被解释成short, 请看下面的解释
s += 32768; //报错,显然32768是不能解释成short的,只能解释成int
s+=(s+1); //报错,右端是复杂表达式,1被解释成int

       从上面可以看出一个规则,那就是,复杂表达式计算中的隐式良性类型转换,一概默认直接解释或转换成4字节对齐的CLS兼容类型,如int/long,理由很简单:既省了麻烦,又能保证性能(不仅有运行效率时的考虑,而且还有代码生成的考虑,因此这种考虑是一步到位的),例如,s=s+1中的1,被解释成了int,而不是short,这是合理的。但如果不是复杂表达式,而仅仅只是一个简单的常数量的话,编译器在parse时便不会遵循"4字节对齐的CLS兼容类型",它将根据其他部分来自动判别最适合的类型(这种做法也是合理的,因为此时仍处于parse阶段,迅速判断类型是否兼容才是第一要务,性能不性能、对不对齐是次要问题,所以,此时对数字常量的类型解释也用不着一步到位,遵循最快最省事原则即可...),比方说s+=1和s+=32768这两个例子,前者1被解释成short,所以合法,后者32768将被迫解释成int,左右式类型不兼容,所以出错。同理,上述解释也适用于s+=(s+1)这个例子:(s+1)是复杂表达式,不是简单数字常量,所以被解释成(int)s+(int)1,而不是(short)s+(short)1,从而报错。 

       请注意上述解释主要针对parse阶段。实际上,到了代码生成阶段,出于性能等目的,类型可能还会得到进一步提升,如s+=1这个例子,实际上在IL代码生成阶段,这个parse阶段识别出来的(short)1最终被提升为了(int)1,这应该便是瑞克观察到的IL参数4字节对齐的现象了。其实,为避免混淆,我觉得一般使用者理解到parser层面便足矣,因为类型的判别和兼容性检查在代码生成阶段已经不是关键问题了,不过当然,只要是良性类型提升,无论哪个阶段都是可以做的,甚至,只要在parse阶段编译器已经获得了正确的类型信息,那么,在代码生成阶段对变量再进行非良性的类型转换,这也是有保障的设计行为。至此,我相信解释应该完整了...
更多精彩内容其他人还在看

开源跨平台运行服务插件TaskCore.MainForm

这篇文章主要为大家详细介绍了开源跨平台运行服务插件TaskCore.MainForm的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

CKEditor自定义按钮插入服务端图片

这篇文章主要为大家详细介绍了CKEditor自定义按钮插入服务端图片的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Asp.net Web Api实现图片点击式图片验证码功能

现在验证码的形式越来越丰富,今天要实现的是在点击图片中的文字来进行校验的验证码。下面通过本文给大家分享Asp.net Web Api实现图片点击式图片验证码功能,需要的的朋友参考下吧
收藏 0 赞 0 分享

WPF实现ScrollViewer滚动到指定控件处

这篇文章主要为大家详细介绍了WPF实现ScrollViewer滚动到指定控件处,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

WPF实现带全选复选框的列表控件

这篇文章主要为大家详细介绍了WPF实现带全选复选框的列表控件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Asp.net MVC 中利用jquery datatables 实现数据分页显示功能

这篇文章主要介绍了Asp.net MVC 中利用jquery datatables 实现数据分页显示功能,非常不错,具有参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

asp.net 利用NPOI导出Excel通用类的方法

本篇文章主要介绍了asp.net 利用NPOI导出Excel通用类的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

VS2015自带LocalDB数据库用法详解

这篇文章主要为大家详细介绍了VS2015自带LocalDB数据库的用法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

SignalR Self Host+MVC等多端消息推送服务(一)

这篇文章主要为大家详细介绍了SignalR Self Host+MVC等多端消息推送服务,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

SignalR Self Host+MVC等多端消息推送服务(二)

这篇文章主要为大家详细介绍了SignalR Self Host+MVC等多端消息推送服务的第二篇,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多