I am writing a static analysis tool for CIL. Control flow analysis would be simplified if finally blocks could be interpreted as try-catch blocks with a rethrow inside the catch. In C#, I fail to see the difference between
try
{
// ...
}
finally
{
// finally code here
}
and
try
{
// ...
}
catch
{
// finally code here
throw;
}
or between
try
{
// ...
}
catch(Exception e)
{
// catch code here
}
finally
{
// finally code here
}
and
try
{
try
{
// ...
}
catch (Exception e)
{
// catch code here
}
}
catch
{
// finally code here
throw;
}
There are even a finally block and endfinally instructions in the CIL. There must be a difference, is there?
No - a finally
block is executed even if no exception is thrown, and also even if another catch
block catches the exception. (That's true whether the catch
block then throws an exception itself or not.)
Oh, and a finally
block will also be executed if the try
block returns from the method.
Basically, if you want code to always execute when execution leaves the statement, finally
is what you want. Although in C# I find I rarely write an explicit finally
block - a using
statement nearly always makes the code simpler.
To add to Jon's -- correct, of course -- answer: you are actually describing a try-fault
block. That is, a try-fault
block is equivalent to try
followed by catch
-everything and automatic re-throw
.
C# does not support try-fault
blocks but CIL does, so if you're ever reading IL and you see a fault
block, now you know what it is.
Also, it is correct to say that
try{}
catch {}
finally {}
is equivalent to
try
{
try { }
catch { }
}
finally { }
And in fact inside the C# compiler that's what it does; all try-catch-finally blocks are rewritten into a nested try-catch inside a try-finally. That is a simplifying assumption that can help when writing a static analyzer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With