C# |=和&;=上短路C语言中的赋值运算符#

C# |=和&;=上短路C语言中的赋值运算符#,c#,short-circuiting,C#,Short Circuiting,我知道|和&&在C#中被定义为短路运算符,这种行为由语言规范保证,但是|=和&=也短路吗 例如: private bool IsEven(int n) { return n % 2 == 0; } private void Main() { var numbers = new int[] { 2, 4, 6, 8, 9, 10, 14, 16, 17, 18, 20 }; bool allEven = true; bool anyOdd = false;

我知道
|
&&
在C#中被定义为短路运算符,这种行为由语言规范保证,但是
|=
&=
也短路吗

例如:

private bool IsEven(int n)
{
    return n % 2 == 0;
}

private void Main()
{
    var numbers = new int[] { 2, 4, 6, 8, 9, 10, 14, 16, 17, 18, 20 };

    bool allEven = true;
    bool anyOdd = false;

    for (int i = 0; i < numbers.Length; i++)
    {
        allEven &= IsEven(numbers[i]);
        anyOdd |= !IsEven(numbers[i]);
    }
}
private bool IsEven(int n)
{
返回n%2==0;
}
私有void Main()
{
变量数=新的整数[]{2,4,6,8,9,10,14,16,17,18,20};
布尔·阿列文=真;
bool anyOdd=false;
for(int i=0;i
当点击9条目时,
allEven
变为false,这意味着所有后续条目都是不相关的-
allEven
的值对于以后对该表达式的所有调用都保证为false。这同样适用于
anyOdd
,它在看到9时被设置为true,并且对于该表达式的所有后续调用都将保持true

那么,
&=
|=
快捷方式,或者
IsEven
保证在每次迭代中都被调用?对于这种情况,语言规范中是否定义了任何行为?是否存在这样的短路问题

但是
|=
&=
是否也短路


否。
&=
是操作
&
的等价物,而不是短路逻辑运算符。

否,
&=
运算符没有进行短路评估

它们是伪运算符,编译器将其转换为使用
&
|
运算符

此代码:

allEven &= IsEven(numbers[i]);
完全等同于:

allEven = allEven & IsEven(numbers[i]);
如果需要短路检查,则必须使用短路版本的运算符写出:

allEven = allEven && IsEven(numbers[i]);
没有
&&=伪运算符,但上面的代码正是编译器在有伪运算符的情况下所要做的。

C#规范保证从左到右精确计算两侧一次,并且不会发生短路

5.3.3.21嵌入表达式的表达式的一般规则

以下规则适用于这类表达式:括号表达式(§7.6.3)、元素访问表达式(§7.6.6)、带索引的基本访问表达式(§7.6.8)、递增和递减表达式(§7.6.9、§7.7.5)、强制转换表达式(§7.7.6)、一元+、-、~、*表达式、二进制+、-、*、/、%、=、=、=、!=,是,&,|,^表达式(§7.8,§7.9,§7.10,§7.11),复合赋值表达式(§7.17.2),选中和未选中表达式(§7.6.12),加上数组和委托创建表达式(§7.6.10)

这些表达式中的每一个都有一个或多个子表达式,这些子表达式按固定顺序进行无条件计算

复合运算符的C#规范规定:

7.17.2复合赋值

通过应用二进制运算符重载解析(§7.3.4)来处理形式为
x op=y
的操作,就像该操作是写入
x op y
一样。那么

  • 如果所选运算符的返回类型隐式转换为
    x
    类型,则该操作的计算结果为
    x=x op y
    ,但
    x
    仅计算一次

  • 否则,如果所选运算符是预定义运算符,如果所选运算符的返回类型可显式转换为
    x
    类型,如果
    y
    可隐式转换为
    x
    类型,或者该运算符是移位运算符,则该操作的计算结果为
    x=(T)(x op y)
    ,式中,T是
    x
    的类型,但
    x
    仅计算一次

在您的情况下,
op
&
。短路行为反映了
&
/
|
的短路行为,而不是
&
/
|


请注意,这仅指在单线程场景中可见的行为。因此,如果右侧没有在这种情况下可以观察到的副作用,编译器或JITter仍然可以自由地忽略计算

在您的示例中,编译器可以在知道结果后自由终止循环,因为没有这样的副作用。但这并不是必须的


特别是,计时不算作这样的副作用,因此您不能依赖代码具有恒定的运行时间。这在安全上下文中可能会有问题,因为它会引入定时侧通道。

-1不,这是不正确的。当在booelan上使用时,它们不是按位运算符。@Guffa我觉得将它们视为按位运算符是很有帮助的,但是是的,你是对的。对于bool操作数,&计算其操作数的逻辑AND;也就是说,当且仅当其两个操作数都为真时,结果才为真。不管第一个操作符的值是多少,@Roman,&操作符都会对这两个操作符进行求值,我不确定这与您发布的内容有关。Guffa和我都意识到了这一点……事实上,这更多是为了像我这样的读者,而不是你,我看到你们都意识到了这一点。伪运算符和它们的行为是在语言规范中定义的,还是它们是由IDE/编译器提供的附加语法糖?@多项式:这在“7.17.2复合赋值”一章中有介绍在语言规范中。回答得很好。我会记住不要依赖于每次迭代都调用它。关于侧通道攻击也很重要。