What will be empty to catch and throw a block?
I know the next block is catch and throw
superfluous, I am curious how much damage it can do?
Can the compiler optimize it in release mode? Or will it catch this exception anyway and reverse engineer it? If this is the latter case, what performance penalty will it result in?
try
{
//...
}
catch {
throw;
}
source to share
Optimization
The compiler will not optimize this, even in a Release build.
Accept the following test application:
public class Program {
public static void Main(string[] args) {
try {
CallsThrow();
}
catch(Exception ex) {
Console.WriteLine("Main() caught exception: " + ex.Message);
}
Console.Read();
}
private static void CallsThrow() {
try {
Throw();
}
catch {
throw;
}
}
private static void Throw() {
throw new Exception("Here my exception.");
}
}
Using ILSpy , we can view the output binary at the IL level . We can see that try
/ catch
in CallsThrow
still exists in our binary Release:
.method private hidebysig static
void CallsThrow () cil managed
{
// Method begins at RVA 0x2094
// Code size 11 (0xb)
.maxstack 1
.try
{
IL_0000: call void JunkCSharpConsole.Program::Throw()
IL_0005: leave.s IL_000a
} // end .try
catch [mscorlib]System.Object
{
IL_0007: pop
IL_0008: rethrow
} // end handler
IL_000a: ret
} // end of method Program::CallsThrow
Benchmark
Code:
public class Program
{
public static void Main(string[] args) {
const int N = 100000000;
#if DEBUG
const string mode = "Debug";
#else
const string mode = "Release";
#endif
Console.WriteLine("Testing {0} iterations in {1} mode:", N, mode);
// Attempt to JIT / cache
CallsThrowWithTryCatch(false);
CallsThrowWithoutTryCatch(false);
// Test with try/catch+throw
var s1 = Stopwatch.StartNew();
for (int i = 0; i < N; i++ )
CallsThrowWithTryCatch(false);
s1.Stop();
Console.WriteLine(" With try/catch: {0} ms", s1.ElapsedMilliseconds);
// Test without try/catch+throw
var s2 = Stopwatch.StartNew();
for (int i = 0; i < N; i++)
CallsThrowWithoutTryCatch(false);
s2.Stop();
Console.WriteLine(" Without try/catch: {0} ms", s2.ElapsedMilliseconds);
var pct = (s1.ElapsedMilliseconds - s2.ElapsedMilliseconds) / (double)s1.ElapsedMilliseconds * 100.0;
Console.WriteLine("No try/catch faster by {0:.02}%", pct);
// Just show that it works
try {
CallsThrowWithTryCatch(true);
}
catch (Exception ex) {
Console.WriteLine("Main() caught exception: " + ex.Message);
}
// Wait to exit
Console.WriteLine("Press ENTER to exit.");
Console.Read();
}
private static void CallsThrowWithTryCatch(bool doThrow) {
try {
Throw(doThrow);
}
catch {
throw;
}
}
private static void CallsThrowWithoutTryCatch(bool doThrow) {
Throw(doThrow);
}
private static void Throw(bool doThrow) {
if (doThrow)
throw new Exception("Here my exception.");
}
}
Results:
Testing 100000000 iterations in Debug mode: With try/catch: 1492 ms Without try/catch: 1474 ms No try/catch faster by 1.22% Main() caught exception: Here my exception. Press ENTER to exit. Testing 100000000 iterations in Release mode: With try/catch: 598 ms Without try/catch: 458 ms No try/catch faster by 23.42% Main() caught exception: Here my exception. Press ENTER to exit.
We can see that yes, there is a performance penalty associated with even an empty try
/ catch
. In Debug builds this is not that important, but the Release build showed a significant 23.42% improvement by removing try
/ catch
.
source to share