今天看书时,突然发现了一个很有趣的问题:
short s = 1;
(1)s=s+1;
(2)s+=1;
编译时s=s+1提示出错,不能隐式转换,必须强制转换;而s+=1却能顺利编译。
通过在网上查找原因,得出结论:s=s+1中"+"操作符自动向较高精度提升了字符类型,s+1为int 类型,与左边的short类型不匹配,必须强制转换;
s+=1中"+="操作符在返回结果之前不仅提升了字符类型,而且自动进行了类型转换。
下面是摘自网上一篇详细的介绍
s=s+1与s+=1在官方网站上据说是等效的,可是在实际的应用中,它们之间还是有一点小小的区别,这些区别造成了一些困惑,现在就对这些区别做一些解释。
前几天一个很牛的朋友问我:“s=s+1与s+=1有什么区别?”,我认为他在开玩笑,因为以这个朋友的实力,不会不知道这个的,我认为这是一个陷阱,赶快到MSDN上 进行查询,得到的结果是:
使用 += 赋值运算符的表达式,
x += y
等效于
x = x + y。既然MSDN上都说了“等效”,当然它们应该是一样的。我的朋友立即给我发过来一段代码,
short s = 1;
s = s + 1;
short n = 1;
n += 1;
Console.ReadKey();
其中s=s+1编译错误:无法将类型“int”隐式转换为“short”。存在一个显式转换(是否缺少强制转换?),并且定位在s=s+1这一行,从
这里看两个还真的不等效。
于是将代码改写为
short s = 1;
s = (short)(s + 1);
short n = 1;
n += 1;
Console.ReadKey();
编译通过,于是推测s=s+1这个表达式中,1被默认的看为整型int,根据运算规则,s+1中的s也会隐式的转换成int,于是结果就变成
了int类型,由于int类型比short类型的精度高,所以将int赋值给short时,需要进行强制类型转换,于是,我又编写了下面的代码
short s = 1;
short k = 2;
s = s+k;
short n = 1;
n += 1;
Console.ReadKey();
编译仍然不能通过,提示信息错误无法将类型“int”隐式转换为“short”。存在一个显式转换(是否缺少强制转换?),晕倒,short+short得出的结果仍然是int类型,为了测试这个想法,于是编写代码如下:
short s = 1;
short k = 2;
Console.WriteLine((s + k).GetType().FullName);
short n = 1;
n += 1;
Console.ReadKey();
得到的结果是System.Int32(在c#中,short对应System.Int16,int对应System.Int32),在C#中,为数值类型和字符串类型预定义了二元 + 运算符。其实+运算符应该也是一个函数调用,只是这个函数的名字比较特殊罢了。
当一个函数的名称相同,而要根据参数的类型或者参数的个数的不同而有不同的实现的时候,需要进行函数的重载,问题可能就是出现在这个+运算符的重载了。
推测在系统的内部,系统只重载了 int operator+(int,int)这样的函数,在进行short+short运算时,系统寻找精确的匹配,但是没有找到,可是将short升级为int是一个自动的过程,于是系统调用了int operator(int,int)这个函数,得到的结果也就被转化为int类型,就出现了上面的错误。
而+=这个运算符与+运算符一样,但是系统重载了short operator +=(short,short)或者short operator +=(int,int),这个函数的具体实现没办法看到,可是据推测应该是这样
short operator+=(int b)
{
return (short)(this+b);
}
也就是在返回数据的结果前,系统自己做了强制类型转换。为了验证这个思想,我又做了两件事情。
第一:对short类型扩展一个方法(vs2008的扩展方法),该方法实现的是两个short类型的变量的加和,但是在返回结果前,对结果进行强制类型转换。代码如下:
namespace ConsoleApplication1
{
static class Myshort
{
public static short add(this short a,short b)
{
return (short)(a+b);
}
}
}
重新编写代码
short s = 1;
short k = 2;
s=s.add(k);
没有任何问题,编译通过。
第二:对源代码进行反编译,看看反编译的代码
源代码如下:
static void Main(string[] args)
{
short s = 1;
short k = 2;
s=s.add(k);
short n = 1;
n += 1;
Console.ReadKey();
}
生成的反编译的代码:
private static void Main(string[] args)
{
short s = 1;
short k = 2;
s = s.add(k);
short n = 1;
n = (short) (n + 1);
}
对比可以知道,+=运算符果然在返回结果之前系统进行了强制类型转换。