Do C# exception filters introduced in VS2015 have any effect on performance, memory usage or the stack when an exception is thrown?
Exception filter:
try { … }
catch (Exception e) when (e.Message == "Hello world")
{
// do stuff
}
Verses traditional catch and re-throw:
try { … }
catch (Exception e)
{
if (e.Message == "Hello world")
{
// do stuff
}
else
{
throw;
}
}
Intel Core i7, .NET Core 2.2.5
+-----------------+--------+----------------------+-----------------+----------------+-----------------+------+------------+-------+-------+------------+
| Method | N | SearchedQueryIsMatch | Mean | Error | StdDev | Rank | Gen 0 | Gen 1 | Gen 2 | Allocated |
+-----------------+--------+----------------------+-----------------+----------------+-----------------+------+------------+-------+-------+------------+
| ExceptionFilter | 1 | False | 21.29 us | 0.3780 us | 0.6912 us | 2 | 0.0916 | - | - | 440 B |
| IfStatement | 1 | False | 40.35 us | 0.7339 us | 0.6505 us | 3 | 0.0610 | - | - | 440 B |
| ExceptionFilter | 1 | True | 19.28 us | 0.3831 us | 0.8409 us | 1 | 0.0305 | - | - | 216 B |
| IfStatement | 1 | True | 19.08 us | 0.4230 us | 0.6331 us | 1 | 0.0305 | - | - | 216 B |
| ExceptionFilter | 1000 | False | 20,813.47 us | 413.2388 us | 537.3272 us | 5 | 93.7500 | - | - | 440000 B |
| IfStatement | 1000 | False | 40,412.30 us | 645.9158 us | 604.1901 us | 6 | 76.9231 | - | - | 440000 B |
| ExceptionFilter | 1000 | True | 18,433.85 us | 257.8815 us | 228.6052 us | 4 | 31.2500 | - | - | 216000 B |
| IfStatement | 1000 | True | 18,510.49 us | 366.2362 us | 324.6588 us | 4 | 31.2500 | - | - | 216000 B |
| ExceptionFilter | 100000 | False | 2,037,740.01 us | 46,797.1438 us | 57,471.0953 us | 8 | 10000.0000 | - | - | 44000000 B |
| IfStatement | 100000 | False | 4,057,642.15 us | 80,944.2280 us | 179,366.8182 us | 9 | 10000.0000 | - | - | 44000000 B |
| ExceptionFilter | 100000 | True | 1,835,382.75 us | 35,810.5411 us | 42,629.9019 us | 7 | 5000.0000 | - | - | 21600000 B |
| IfStatement | 100000 | True | 1,833,703.56 us | 34,189.6215 us | 31,980.9932 us | 7 | 5000.0000 | - | - | 21600000 B |
+-----------------+--------+----------------------+-----------------+----------------+-----------------+------+------------+-------+-------+------------+
public class Program
{
[CoreJob]
[RPlotExporter, RankColumn, MemoryDiagnoser]
public class CollectionsContains
{
private const string SearchedMessage = "hello world";
[Params(1, 1_000, 100_000)]
private int N;
[Params(true, false)]
private bool SearchedQueryIsMatch;
[Benchmark]
public void ExceptionFilter() => ExecuteTestFor(exception =>
{
try
{
throw exception;
}
catch (Exception ex) when (ex.Message == SearchedMessage)
{
}
});
[Benchmark]
public void IfStatement() => ExecuteTestFor(exception =>
{
try
{
throw exception;
}
catch (Exception ex)
{
if (ex.Message == SearchedMessage)
{
return;
}
throw;
}
});
private void ExecuteTestFor(Action<Exception> testedExceptionHandling)
{
for (int i = 0; i < N; i++)
{
try
{
var exception = new Exception(SearchedQueryIsMatch ? SearchedMessage : Guid.NewGuid().ToString());
testedExceptionHandling(exception);
}
catch
{
}
}
}
}
private static void Main() => BenchmarkRunner.Run<CollectionsContains>();
}
The new C# 6.0 feature of exception filtering basically flips the logic around of catching an exception and then checking conditions.
The difference is:
So I'm not sure what the exact performance implications are, but I think you're better off overall.
If the condition's not met, then you don't have to unwind the stack, or incur the cost of catching and rethrowing (the exception isn't caught/rethrown.. it's just not caught at all), or perform any of the other logic you may have included inside the catch statement.
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