簡體   English   中英

C#如何計算包含賦值的表達式?

[英]How does C# evaluate expressions which contain assignments?

我有C / C ++背景。 我遇到了一種在C#中交換兩個值的奇怪方式。

int n1 = 10, n2=20;
n2 = n1 + (n1=n2)*0;

在C#中,上面兩行在n1n2之間進行交換。 這對我來說是一個驚喜,因為在C / C ++中,結果應該是n1=n2=20

那么,C#如何評估表達式 它看起來像上面的+被視為一個function calling我。 以下解釋似乎是可行的。 但似乎對我很熟悉。

  1. 首先執行(n1=n2) 因此n1=20
  2. 那么n1 n1+ (n1=n2)*0中的n1+ (n1=n2)*0還不是20。 它被視為一個函數參數,因此被推入堆棧並且仍為10.因此, n2=10+0=10

在C#中,子表達式按從左到右的順序進行計算,副作用按此順序生成。 這在C#5規范的第7.3節中定義:

表達式中的操作數從左到右進行計算。

重要的是要認識到子表達式評估的順序與優先級(也就是操作順序)和關聯性無關。 例如,在類似A() + B() * C()的表達式中。 C#中的評估順序始終是A()B()C() 我對C / C ++的有限理解是這個順序是一個編譯器實現細節。

在您的示例中,首先計算n1(10)的左操作數。 然后評估(n1=n2) 其結果是n2(20)的值,產生分配給n1的副作用。 n1現在是20.然后20 * 0的乘法產生0.然后計算10 + 0並且將結果(10)分配給n2。 因此,最終的預期狀態是n1 = 20且n2 = 10。

Eric Lippert在本網站他的博客上詳細討論了這個問題。

好的,這可能最好用IL操作碼來解釋。

IL_0000:  ldc.i4.s    0A 
IL_0002:  stloc.0     // n1
IL_0003:  ldc.i4.s    14 
IL_0005:  stloc.1     // n2

前4行有點自我解釋ldc.i4加載變量(int大小為4)只有堆棧而stloc。*將值存儲在堆棧頂部

IL_0006:  ldloc.0     // n1
IL_0007:  ldloc.1     // n2
IL_0008:  stloc.0     // n1
IL_0009:  stloc.1     // n2

這些行基本上就是你所描述的。 每個值只加載堆棧,在n2之前加載n1然后存儲但是在n2之前存儲n1(因此交換)

我相信這是.NET規范中描述的正確行為。

mikez還添加了更多細節並幫助我找到答案,但我相信答案在7.3.1中得到了解釋

當操作數出現在具有相同優先級的兩個運算符之間時,運算符的關聯性控制執行操作的順序:

  • 除了賦值運算符和空合並運算符之外,所有二元運算符都是左關聯的,這意味着操作是從左到右執行的。 例如,x + y + z被評估為(x + y)+ z。

  • 賦值運算符,空合並運算符和條件運算符(?:)是右關聯的,這意味着操作從右到左執行。 例如,x = y = z被評估為x =(y = z)。 可以使用括號控制優先級和關聯性。 例如,x + y * z首先將y乘以z然后將結果添加到x,但是(x + y)* z首先添加x和y,然后將結果乘以z。

這里重要的是評估操作的順序,以便實際評估的是什么

n2 = (n1) + ((n1=n2)*0)

其中(n1)+(..)通過二元運算符從左到右進行求值。

閱讀規范,它會告訴你實情:

7.5.1.2參數列表的運行時評估

參數列表的表達式始終按其編寫順序進行計算。 因此,這個例子

 class Test { static void F(int x, int y = -1, int z = -2) { System.Console.WriteLine("x = {0}, y = {1}, z = {2}", x, y, z); } static void Main() { int i = 0; F(i++, i++, i++); F(z: i++, x: i++); } } 

產生輸出

 x = 0, y = 1, z = 2 x = 4, y = -1, z = 3 

如果將代碼更改為:您可以看到它也適用於算術運算:

int n1 = 10, n2=20;
n2 = (n1=n2) * 0 + n1;

現在, n1n2等於20

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM