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