一道数学运算题
事由是同事在工作中遇到的一个小问题,然后发到群里大家研究出来原因到底在哪里,问题是这样的:
int? a = 2; int? b = 1; var res1= ((a ?? 0) + (b ?? 0)); var res2 = (a ?? 0 + b ?? 0);
求res1,res2的值?
我相信,大部分程序员都会有这样的答案,都会说3,但是知道肯定不会都是3这么简单的,于是我把它封装成一个类里的两个方法。
public class Class1 { public void A() { int? a = 2; int? b = 1; var res1 = ((a ?? 0) + (b ?? 0)); } public void B() { int? a = 2; int? b = 1; var res2 = (a ?? 0 + b ?? 0); } }
使用反编译神器Reflector反编译来查看究竟。
public void A() { int? a = 2; int? b = 1; int? CS$0$0000 = a; CS$0$0000 = b; int res1 = (CS$0$0000.HasValue ? CS$0$0000.GetValueOrDefault() : 0) + (CS$0$0000.HasValue ? CS$0$0000.GetValueOrDefault() : 0); } public void B() { int? CS$0$0001; int? a = 2; int? b = 1; int? CS$0$0000 = a; int res2 = CS$0$0000.HasValue ? CS$0$0000.GetValueOrDefault() : (((CS$0$0001 = b) = CS$0$0001.HasValue ? new int?(CS$0$0001.GetValueOrDefault()) : null).HasValue ? CS$0$0001.GetValueOrDefault() : 0); }
从反编译出来的代码可以很清楚的看到,方法A很好的遵循了我们想象中的一般运算的顺序,也是括号起到的应有作用,先算左边,再算右边,再将两者相加,而方法B的运算顺序则完全被打乱了(其实不是被打乱,只是和我们脑中想象出来以为的运算顺序不符,这也是我们错误的点),特别是三目运算的后面,显得非常复杂,但是从 CS$0$0000.HasValue ? CS$0$0000.GetValueOrDefault() : ……………………可以看出,如果a有值的话,就直接把a返回出去了,而不进行后续的运算。
再思考,为什么会出现这样的差异,很明显,只有运算符的优先级才会影响运算的顺序,查询MSDN(http://msdn.microsoft.com/zh-cn/library/6a71f45d(v=vs.100).aspx)得知:加减运算(+、-)比条件运算、null合并运算(?:、??)都高得多。
答案:
res1=3; res2=2;