5

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

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. 我的第三个代码片段总是会给出与第一个相同的结果吗?
  2. 为什么第一个代码片段不做与第二个相同的事情?
4

3 回答 3

11

优先级不是关于排序操作- 它是关于将操作绑定在一起。执行顺序总是从左到右。例如,如果你写:

int a = x * (y / z);

thenx仍然在之前进行评估y / z

所以在这个表达式中:

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

我们有:

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

从混乱中可以清楚地看出,这段代码很糟糕——我很高兴你正在重构它,使其脱离当前的形式。

于 2013-09-17T16:52:00.090 回答
0

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

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;
}

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

这会确定字符串的长度,然后对字符串进行变异,然后获取长度并进行比较。

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

于 2013-09-17T16:51:46.940 回答
0

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

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

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

于 2013-09-17T17:03:45.487 回答