C# Tester-Doer Pattern

This C# article tests the performance of the tester-doer pattern. It compares try and catch.

Tester-doer. The tester-doer pattern describes certain methods.

These methods first test the input before doing anything with it. We test the tester-doer pattern. In some programs, exception handling and tester-doer are interchangeable.

Tester-doer pattern timing

If check:  780 ms
Try-catch: 609 ms [faster]

 

 

Intro. First, Microsoft introduces the tester-doer pattern as a solution to exception performance. TryGetValue is an example of the tester-doer pattern. Tester-doer methods often are called within an if-statement.

 

Consider the Tester-Doer pattern for members that may throw exceptions in common scenarios to avoid performance problems related to exceptions. Exceptions and Performance, MSDN

 

Example. If your method fails frequently, you usually should test for failure to avoid an exception. However, what if your code doesn't fail often? How expensive is a try-catch block that is almost never used, but still present in the method?

 

Next: This section compares code that tests first, and code that assumes a certain case.

C# program that uses tester-doer pattern

using System.Collections.Generic;

class Program
{
    static void Main()
    {
	var d = new Dictionary<string, int>();
	if (!d.ContainsKey("ok"))
	{
	    d.Add("ok", 1);
	}
    }
}

C# program that uses try-catch

using System.Collections.Generic;

class Program
{
    static void Main()
    {
	var d = new Dictionary<string, int>();
	try
	{
	    d.Add("ok", 1);
	}
	catch
	{
	}
    }
}

Figure A. The first example here uses the tester-doer pattern to handle cases where the key is in the Dictionary. This will always avoid exceptions related to the Dictionary. We use ContainsKey to test.

ContainsKeyDictionary

Figure B. This code skips checking for the unlikely case where the key is found. It assumes everything is in its right place and nothing bad will happen. We use a try statement and a catch statement.

TryCatch

 

Discussion. I found that in this example it is best to write code that assumes success when success is most likely. In other words, you should not test for cases that are unlikely or exceptional. Leave the unlikely stuff to exception-handling.

 

Note: 4000000 iterations were tested. Clear() method on Dictionary was called in each iteration. Code samples A and B were used.

Benchmark

This means that exceptions that are not thrown are sometimes cheaper than lots of manual if checks. It follows that if your checks are really fast, the difference would be smaller.

Tip: The example that catches rare exceptions can use application-wide logging methods to record them and put them in a central place.

Tip 2: I usually avoid writing exceptions to disk. I often just view them while the application is running.

 

Summary. We looked at the tester-doer pattern in the C# programming language. Exceptions are critical and can be faster in certain cases than always checking for failure. But in many contexts, tester-doer is the best choice.