You know there are performance problems with exceptions, but want to test this and compare exceptions to null checks. Here we develop benchmarks and find the best way for high-performance C# code.
~~~ Exception performance test in C# ~~~ Based on .NET 3.5 SP1. Using null checks was significantly faster than try/catch blocks. GetA - null checks: 95 ms GetB - uses try: 607 ms
Here I tested exception handling with try/catch against a method that carefully tests for null to avoid failures. First, we see the code that demonstrates the difference between these two methods.
=== Program that shows exceptions (C#) ===
using System;
class Program
{
static void Main()
{
int[] arr = new int[] { 1, 2, 3 };
Console.WriteLine(GetA(arr));
Console.WriteLine(GetB(arr));
Console.WriteLine(GetA(null));
Console.WriteLine(GetB(null));
}
/// <summary>
/// Get the first element, checking the parameter for null.
/// </summary>
static int GetA(int[] arr)
{
if (arr != null)
{
return arr[0];
}
else
{
return 0;
}
}
/// <summary>
/// Get the first element, catching exceptions without checking for null.
/// </summary>
static int GetB(int[] arr)
{
try
{
return arr[0];
}
catch
{
return 0;
}
}
}
=== Output of the program ===
1
1
0
0Description of the code. The above console program demonstrates two methods. The first one, GetA(), accepts an int[] array as a parameter. It then tests the int[] array for null. It returns the value of the first element in that array, or zero if the array doesn't exist.
Further description. The second method, GetB(), works the same as the first one but uses a try/catch block to catch the case where the array is null. It also returns 0 if the array parameter is null. In the Main() method, we see that the two methods, GetA() and GetB(), function the same on both non-null arrays and null arrays.
Here we see a benchmark of the two methods. This will show the performance difference between a method that checks its variables for null to detect error cases, and a method that throws exceptions when errors occur. The error cases never occur in the benchmark, meaning that the catch statement is never executed and the parameter is never null. This way, we see the cost of null checks versus exceptions that are never thrown.
=== Data used in benchmark (C#) ===
int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; // Dummy code
=== Code tested in tight loops (C#) ===
int v = GetA(arr);
if (v == 5) // Dummy code for benchmark
{
i++;
}
int v = GetB(arr);
if (v == 5) // Dummy code for benchmark
{
i++;
}
=== Notes on benchmark ===
Iterations: 100000000
Results are shown at the top.
Methods GetA and GetB shown in previous example.Here we saw that when an exception is not thrown in the C# code, the try/catch block can have a negative effect on performance anyway. When an exception is actually thrown, which isn't tested in the benchmark, performance suffers even more.