为什么在 finally 部分重置此变量时,在 try 块中返回变量不会更改返回值的值?
Why does returning a variable in a try block not change the value of the returned thing when this variable is reset in the finally section?
我不太明白下面代码中的指令是如何流动的。
finally
的主体保证在方法 return 之前执行。如果是这样,return 值应该是 0 而不是 1。
你能解释一下为什么 return 的值在 finally
已重置为 0 的情况下仍然为 1 的内部机制吗?
class Container
{
int data = 0;
public int Retrieve()
{
try
{
Inc();
return data;
}
finally
{
Reset();
//return data;
}
}
void Reset()
{
data = 0;
WriteLine("Reset");
}
void Inc() => data++;
}
class ReturnInTry
{
static void Main()
{
Clear();
WriteLine("Start");
WriteLine(new Container().Retrieve());
WriteLine("End");
}
}
因为当return指令被执行时,它会在CPU堆栈中压入要returned的值。
然后执行 finally 块,但它不会修改已经推送的值。
因此,在方法 PROC RET 之后,调用者 POP 值并拥有已推送的值,但数据本身已被重置。
因此,再次调用该方法将return 0.
这意味着先执行return语句,然后执行finally
中的代码,所以结果是先前存储的并且改变data
不会改变这个存储在堆栈中 结果。
我们可以使用例如 ILSpy 检查:
.method public hidebysig
instance int32 Retrieve () cil managed
{
// Method begins at RVA 0x4cf4
// Code size 30 (0x1e)
.maxstack 1
.locals init ( [0] int32 )
.try
{
// Inc();
IL_0002: ldarg.0
IL_0003: call instance void ConsoleApp.Container::Inc()
// return data;
IL_0009: ldarg.0
IL_000a: ldfld int32 ConsoleApp.Container::data
IL_000f: stloc.0
IL_0010: leave.s IL_001c
} // end .try
finally
{
// Reset();
IL_0013: ldarg.0
IL_0014: call instance void ConsoleApp.Container::Reset()
// }
IL_001b: endfinally
} // end handler
IL_001c: ldloc.0
IL_001d: ret
} // end of method Container::Retrieve
// Console.WriteLine(new Container().Retrieve());
IL_000c: newobj instance void ConsoleApp.Container::.ctor()
IL_0011: call instance int32 ConsoleApp.Container::Retrieve()
IL_0016: call void [mscorlib]System.Console::WriteLine(int32)
我不太明白下面代码中的指令是如何流动的。
finally
的主体保证在方法 return 之前执行。如果是这样,return 值应该是 0 而不是 1。
你能解释一下为什么 return 的值在 finally
已重置为 0 的情况下仍然为 1 的内部机制吗?
class Container
{
int data = 0;
public int Retrieve()
{
try
{
Inc();
return data;
}
finally
{
Reset();
//return data;
}
}
void Reset()
{
data = 0;
WriteLine("Reset");
}
void Inc() => data++;
}
class ReturnInTry
{
static void Main()
{
Clear();
WriteLine("Start");
WriteLine(new Container().Retrieve());
WriteLine("End");
}
}
因为当return指令被执行时,它会在CPU堆栈中压入要returned的值。
然后执行 finally 块,但它不会修改已经推送的值。
因此,在方法 PROC RET 之后,调用者 POP 值并拥有已推送的值,但数据本身已被重置。
因此,再次调用该方法将return 0.
这意味着先执行return语句,然后执行finally
中的代码,所以结果是先前存储的并且改变data
不会改变这个存储在堆栈中 结果。
我们可以使用例如 ILSpy 检查:
.method public hidebysig
instance int32 Retrieve () cil managed
{
// Method begins at RVA 0x4cf4
// Code size 30 (0x1e)
.maxstack 1
.locals init ( [0] int32 )
.try
{
// Inc();
IL_0002: ldarg.0
IL_0003: call instance void ConsoleApp.Container::Inc()
// return data;
IL_0009: ldarg.0
IL_000a: ldfld int32 ConsoleApp.Container::data
IL_000f: stloc.0
IL_0010: leave.s IL_001c
} // end .try
finally
{
// Reset();
IL_0013: ldarg.0
IL_0014: call instance void ConsoleApp.Container::Reset()
// }
IL_001b: endfinally
} // end handler
IL_001c: ldloc.0
IL_001d: ret
} // end of method Container::Retrieve
// Console.WriteLine(new Container().Retrieve());
IL_000c: newobj instance void ConsoleApp.Container::.ctor()
IL_0011: call instance int32 ConsoleApp.Container::Retrieve()
IL_0016: call void [mscorlib]System.Console::WriteLine(int32)