【问题标题】:Evaluation of expressions within an if statementif 语句中表达式的求值
【发布时间】:2013-09-17 16:48:18
【问题描述】:

在重构一些别人写的代码时,我遇到了一些我不理解的奇怪现象,我希望有人能解释为什么会发生这种情况。

if (mystring.Length != (mystring = mystring.Replace("!#", replacement)).Length)
{
    i = 1;
}
else if (mystring.Length != (mystring = mystring.Replace("#", replacement)).Length)
{
    i = -1;
}

认为会发生在这里,因为括号具有最高优先级,括号内的赋值将首先发生,并且 if 和 else if 块内的任何代码都不会被执行。 以下是我认为这段代码有效的作用:

mystring = mystring.Replace("!#", replacement);
if (mystring.Length != mystring.Length)
{
    i = 1;
}
else
{
    mystring = mystring.Replace("#", replacement);
    if (mystring.Length != mystring.Length)
    {
        i = -1;
    }
}

我认为唯一会发生的事情是对mystring 的更改,因为分配将在比较之前进行。对此进行测试表明,发生的事情实际上更接近于:

string temp1 = mystring.Replace("!#", replacement);
string temp2 = mystring.Replace("#", replacement);
if (mystring.Length != temp1.Length)
{
    i = 1;
}
else if (mystring.Length != temp2.Length)
{
    i = -1;
}
if (i == 1)
{
    mystring = temp1;
}
else
{
    mystring = temp2;
}

如果不清楚,我认为正在发生的事情是在评估表达式的真实性之后对 mystring 进行赋值,而不是像我想象的那样作为评估该表达式的第一部分。我的第三段代码可能无法很好地表达它,但我想不出更好的表达方式!

简而言之:

  1. 我的第三个代码 sn-p 是否总是与第一个代码给出相同的结果?
  2. 为什么第一个代码 sn-p 不做与第二个相同的事情?

【问题讨论】:

  • 这种代码的推理困难正是它应该引发红旗的原因。
  • 这正是布尔表达式不应该有副作用的原因。
  • 我将重写它以使其更具可读性,我只是想确保在此过程中不会更改它的作用! (现在我很好奇发生了什么)
  • 是什么让您相信在if 评估之后 完成了任务?
  • @CodingGorilla 请参阅 Jon Skeet 的回答。

标签: c# syntax


【解决方案1】:

Precedence isn't about ordering operations - 这是关于绑定操作在一起的。执行顺序是始终从左到右。例如,如果你写:

int a = x * (y / z);

那么x 仍然在y / z 之前进行评估。

所以在这个表达式中:

if (mystring.Length != (mystring = mystring.Replace("!#", replacement)).Length)

我们有:

  • 评估mystring.Length(我们将把这个值称为x
  • 评估(mystring = mystring.Replace("!#", replacement)).Length
    • 评估mystring.Replace("!#", replacement)
    • 将结果分配给mystring
    • 取长度(我们称这个值y
  • 比较 xy

从混乱中可以清楚地看出,这段代码很糟糕 - 我很高兴你正在重构它而不是它当前的形式。

【讨论】:

  • 这不是支持 OP 对会发生什么的最初理解吗?将结果分配给 mystring 应该在比较之前发生,他的评论向我表明他认为分配发生在 比较之后。
  • @CodingGorilla 不要迂腐,但请“她的评论”!
  • @CodingGorilla:我对问题的阅读表明,OP 认为 != 运算符的 RHS 将在评估 LHS 之前执行。
  • 这正是我的想法,我可能会更好地表达它!
【解决方案2】:

您原来的代码实际上更接近:

int length1 = mystring.Length;
mystring = mystring.Replace("!#", replacement); // First nested paren on RHS
int length2 = mystring.Length; // second "length" check on RHS
if (length1 != length2)
{
    i = 1;
}

这是因为执行顺序是从左到右的。

这导致字符串的长度被确定,然后字符串被变异,然后长度被获取并比较。

请注意,这种类型的代码几乎总是应该避免的。在布尔表达式中改变数据几乎总是一个坏主意,并且改变您正在检查的相同数据会使这非常混乱。

【讨论】:

    【解决方案3】:

    1:不。在您的第一个代码 sn-p 中,mystring 变量在 if 和 else 中都发生了变化,以评估比较表达式。所以要获得相同的结果,将第三个代码 sn-p 更改为:

    string temp1 = mystring.Replace("!#", replacement);
    string temp2 = **temp1**.Replace("#", replacement);
    if (mystring.Length != temp1.Length)
    {
        i = 1;
    }
    ....
    

    2:因为 mystring 恰好改变了两次

    【讨论】:

      猜你喜欢
      • 2016-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多