我最近遇到了一个讨厌的错误,简化后的代码如下所示:
int x = 0;
x += Increment(ref x);
...
private int Increment(ref int parameter) {
parameter += 1;
return 1;
}
Increment调用后x的值为1!一旦我发现发生了什么,这很容易解决。我将返回值分配给一个临时变量,然后更新 x。我想知道如何解释这个问题。我忽略了规范中的某些内容还是 C# 的某些方面。
最佳答案
+= 读取左侧参数然后读取右侧参数,因此它读取变量,执行递增方法,对结果求和,然后分配给变量。在这种情况下,它读取 0,计算 1 并具有将变量更改为 1 的副作用,求和为 1,然后为变量赋值 1。 IL 证实了这一点,因为它按顺序显示加载、调用、添加和存储。
将 return 更改为 2 以查看结果是 2,确认该方法的返回值是“坚持”的部分。
因为有人问,这里是通过 LINQPad 的完整 IL 及其注释:
IL_0000: ldc.i4.0
IL_0001: stloc.0 // x
IL_0002: ldloc.0 // x
IL_0003: ldloca.s 00 // x
IL_0005: call UserQuery.Increment
IL_000A: add
IL_000B: stloc.0 // x
IL_000C: ldloc.0 // x
IL_000D: call LINQPad.Extensions.Dump
Increment:
IL_0000: ldarg.0
IL_0001: dup
IL_0002: ldind.i4
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stind.i4
IL_0006: ldc.i4.2
IL_0007: ret
请注意,在 IL_000A 行,堆栈包含 x 的加载(加载时为 0)和 Increment 的返回值(为 2)。然后它运行 add
和 STLoc.0
,而不进一步检查 x 的值。
关于c# - ref 参数和赋值在同一行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15881689/