I don't really understand how the instructions flow in the following code.
The body of finally is guaranteed to be executed before the method returns. If so, the return value should be 0 rather than 1.
Could you explain the internal mechanism why the return value is still 1 even though the finally has reset it to 0?
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");
}
}
Because when the return instruction is executed, it PUSHs in the CPU Stack the value to be returned.
Then the finally block is executed but it does not modify the value already pushed.
Thus after the method PROC RET, the caller POPs the value and has what it has been PUSHed, but the data itself has been reseted.
Therefore, calling the method again will return 0.
This means that the return statement is executed first, and the code in
finallyis executed after, so the result is previously stored and changingdatadoes not change this stored in the stack result.try-finally (C# Reference)
We can check that using for example ILSpy:
OpCodes.Stloc_0 Field
OpCodes.ldloc_0 Field
OpCodes.Call Field