2013-12-21 67 views
0
class Program 
{ 
    static void Main(string[] args) 
    { 
    bool success = true; 
    int[] array = { 10, 15, 20 }; 
    foreach (var i in array) 
    success = success && SynchronizeAccount(i); 
    } 

    static bool SynchronizeAccount(int i) 
    { 
    Console.WriteLine(i); 
    return false; 
    } 
} 

輸出爲10.第一步'success'變成false並且從不會爲true,因此c#在第一次迭代後停止循環執行。但是我需要SynchronizeAccount的SIDE效果,而不是'成功'值。布爾AND不評估表達式的兩邊

+9

您的邏輯中比編譯器中的錯誤更可能存在缺陷。 –

+0

@GrantWinney不,它絕對是編譯器中的一個bug;) – MichaC

+1

所以你真的認爲你在編譯器中發現了一個bug,呵呵?在沒有購買財富的情況下贏得100萬美元的彩票更有可能。 –

回答

17

這不是一個錯誤,因爲在幾乎所有的編程語言中,C#都會懶惰地評估&& - 如果左操作數已經爲假,整個表達式永遠不會變爲真,因此不再需要評估表達式的右操作數。

翻轉操作數或更改爲success & SynchronizeAccount以強制評估兩個操作數。

注意,那就是你可以同時適用&&&布爾值的C#一個獨特的功能 - 在大多數其他語言,包括Java和PHP的單一符號(&)是位與,這往往提供完全不同的結果。

+0

正確解釋'success && SynchronizeAccount'和'success&SynchronizeAccount'之間的區別。請注意,在原始問題中也可以使用複合賦值,所以'success&= SynchronizeAccount;'。 –

8

這不是一個錯誤,這是正常的行爲。該&& operator只會評估操作者的右側,如果左側評估爲true

的條件與運算(& &)執行邏輯與它的布爾操作數,但只計算第二個操作數如有必要。

所以在第一次迭代後,success計算結果爲false,並且SynchronizeAccount不會再次調用。

如果要評估SynchronizeAccount不管是什麼它返回,用& operator代替:

foreach (var i in array) 
    success = success & SynchronizeAccount(i); 

或者更簡單地說:

foreach (var i in array) 
    success &= SynchronizeAccount(i); 

或許用一個小的Linq:

bool success = array.Aggregate(true, (b, i) => b & SynchronizeAccount(i)); 
4

這不是一個錯誤,它被稱爲Short-circuit evaluation。如果你真的需要第二種方法,我們&,而不是&&

1

我不會把這當作一個錯誤;它看起來只是一個優化。 「& &」是短路的,因此如果不需要它的結果,編譯器可以優化方法調用。

你可以嘗試改寫這個喜​​歡


foreach (var i in array) { 
    if(!SynchronizeAccount()) 
    success = false; 
} 
+1

不僅允許優化,還需要。如果我說'if(x!= null && x.IsNew){...}',那麼需要'&&'操作符的右邊是***不是***如果左邊 - 手邊是'假'(在這種情況下評估右邊會導致異常)。 –

+0

@JeppeStigNielsen你很對,但我對「停止循環執行」這個詞做出了迴應。它可能只是主題啓發者的觀點,但如果設置「成功」是循環體的唯一動作,編譯器可以通過停止整個循環來優化它。這不會改變任何可見的結果,除了可能花費的時間。 – Netch

1

考慮從你的循環移除success

其他答案很好解釋& vs &&,但我不知道什麼目的success甚至在您的代碼中。既然你打算忽略它並遍歷array中的所有項目,只需在foreach循環內調用SynchronizeAccount並忽略返回的值。

static void Main(string[] args) 
{ 
    int[] array = { 10, 15, 20 }; 
    foreach (var i in array) 
     SynchronizeAccount(i); 
}