在重构其他人编写的代码时,我遇到了一些我不理解的奇怪现象,我希望有人可以解释为什么会这样。
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进行赋值,而不是像我想象的那样评估该表达式的第一部分。我的第三段代码可能无法很好地解决这个问题,但我想不出更好的表达方式!
简而言之:
答案 0 :(得分:11)
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
从混乱中可以清楚地看出,这段代码非常糟糕 - 我很高兴你将它从目前的形式中重构出来。
答案 1 :(得分: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;
}
这是因为执行顺序是从左到右。
这会导致确定字符串的长度,然后字符串发生变化,然后获取并比较长度。
请注意,这种类型的代码几乎总是应该避免的。在布尔表达式中变换数据几乎总是一个坏主意,并且改变你正在检查的相同数据会使这非常令人困惑。
答案 2 :(得分:0)
1:否。在您的第一个代码段中, mystring 变量会在if和else 中更改以评估比较表达式。因此,要获得相同的结果,请将第三个代码段更改为:
string temp1 = mystring.Replace("!#", replacement);
string temp2 = **temp1**.Replace("#", replacement);
if (mystring.Length != temp1.Length)
{
i = 1;
}
....
2:因为 mystring 正好改变了两次