2013-12-21 38 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); 
}