事由是同事在工作中遇到的一個小問題,然后發到群里大家研究出來原因到底在哪里,問題是這樣的:
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;