C# 短路评估跳过条件中的前/后增量
所以,如果我有一个表达式,比如:C# 短路评估跳过条件中的前/后增量,c#,compilation,C#,Compilation,所以,如果我有一个表达式,比如: if (obj != null && i++ % divisor == 0) { .... } 而obj为null,则i从不递增。如果我使用 i++; if (obj != null && i % divisor == 0) { .... } 当然,i是递增的 这是故意的吗?我从优化的角度理解短路计算,但我(错误地)假设编译器会识别增量后表达式并对其进行计算 (如果这是在规范中,我找不到它-只是在这里寻找一些(喘息)意见。)
if (obj != null && i++ % divisor == 0)
{
....
}
而obj
为null
,则i
从不递增。如果我使用
i++;
if (obj != null && i % divisor == 0)
{
....
}
当然,i
是递增的
这是故意的吗?我从优化的角度理解短路计算,但我(错误地)假设编译器会识别增量后表达式并对其进行计算
(如果这是在规范中,我找不到它-只是在这里寻找一些(喘息)意见。)
更新
这是实际的代码
private int _frameNumber = 0;
private void simulator_OnFrameEnd(object sender, System.EventArgs e)
{
_frameNumber++;
if (_visualizer != null && _frameNumber % _config.VisualizerUpdateFrequency == 0)
{
var field = _simulator.GetField(_config.PreviewField);
_visualizer.Update(field, _simulator.FrameTime);
}
if (_frameNumber % _config.OptimizerRegridFrequency == 0)
{
_simulator.UpdateFieldGrids();
}
}
后增量只是语句的后评估。由于从未对语句求值(语句短路),因此跳过了该语句 更直观的方式是将if语句想象为嵌套的:
if (obj != null)
{
if (i++ % divisor == 0)
{
...
}
}
这里我们立即看到,
i
不会增加。类似地,当语句短路时,其行为与上述行为类似,且后增量不排队。这是设计的必然结果。国家:
操作x&y
与操作x&y
相对应,除了
如果x为false,则不计算y,因为
无论y的值是多少,运算都是false。这被称为
“短路”评估
所以,不管你的语句是什么,不管它是否有后增量,如果它短路,它都不会被计算。是的,这是设计的。如果右侧的计算结果为false
,则不会计算左侧,包括可能发生的任何副作用(如增量)
操作x&&y
与操作x&y
相对应,但只有当x
为true
-来源
是的,这是一个旧版本的文档,但语言更清晰,国际海事组织
如果要计算增量,请使用以下方法:
if (_visualizer != null & _frameNumber++ % _config.VisualizerUpdateFrequency == 0)
{
...
}
如果您希望在visualizer==null
但不是模数时执行增量:
var _prevFrameNumber = _frameNumber++;
if (_visualizer != null && _prevFrameNumber % _config.VisualizerUpdateFrequency == 0)
{
...
}
由于\u visualizer!=null
返回false。因此,代码甚至不必检查/执行增量和模运算
如果要切换检查(即如果(\u frameNumber++%5==0&&&u visualizer!=null)
),则\u frameNumber
将递增。。。因为这个动作实际上是执行的
所以是的:这是我们想要的行为,这是设计的。是的,这是设计的。根据规范:
7.12.1
布尔条件逻辑运算符
操作x&&y被评估为(bool)x?(bool)y:false
。在里面
换句话说,首先计算x并将其转换为bool类型。那么,
如果x为true,则计算y并将其转换为bool类型,并且
成为操作的结果。否则,将导致
手术是假的
在您的代码中,y是i++%divisior==0
,因此如果obj
为空,则不会执行i++
。如果您想要这种行为,可以使用&
。如果您必须问这个问题,则表明您的代码不可读。简单。其他人在阅读代码时也会有同样的问题。我建议您构造代码,这样就不会出现这个问题。当然,行为是正确的。你是在误解短路行为是一种优化的情况下工作的。不是这样的事;这是一个重要的保证。如果是可选的优化,那么您不能保证如果(obj!=null&&obj.ToString().Length>10)
不会崩溃@约翰的忠告是好的忠告;这段代码很难阅读,风格也不好。如果您不理解C#中运算符的含义,那么(1)自我教育,(2)编写代码,让不理解其含义的人更容易阅读和维护。一个很好的经验法则是,每个表达式应该完全没有副作用——表达式应该对其值有用,而不是对其效果有用——并且每个单独的语句应该只产生一个副作用。有多重副作用的语句很难解释。@davidlive:正是因为它修改了状态后的表达式才不能执行它!短路操作的全部要点是防止产生右手侧的副作用。@EricLippert我明白了,这当然是有道理的。然而,我的咖啡/啤酒色的《龙之书》让我对这个结构的目的和语义含义有了截然不同的解释。同样,我理解这是一种糟糕的风格——问题是生成代码的“正确性”。(作为一名EE,过去曾在编译器团队(Keil)工作过,我意识到这种级别的“bug”几乎从未在成熟的工具中出现过。因此,我感到困惑。)