一道数学运算题

事由是同事在工作中遇到的一个小问题,然后发到群里大家研究出来原因到底在哪里,问题是这样的:

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;

 

posted @ 2013-06-18 15:18  dotnetgeek  阅读(1324)  评论(8编辑  收藏  举报