Continuation-Passing Style Simplifies Your C# Exception Handling Code

Many lines of code in C# and other imperative languages are seemingly wasted by dealing with overhead such as exception handling and the like. How many times have you written the following type of code?

string[] fileNames;

try
{
    fileNames = Directory.GetFiles(…);
}

catch (Exception)
{
    // There was an error, like the directory isn’t there.
    // This isn’t an error for us, so just use a 0-length array
    // to simplify our later code
    fileNames = new string[0];
}

foreach (string fileName in fileNames)
{
    … do some processing on this file …
}

The basic pattern is, "try to obtain a value by calling this function, but if there’s an error then use a default value." It’s a lot of code, and it gets tiring and unreadable or unmanageable after awhile. This pattern, which is called the hole in the middle pattern, crops up all the time in imperative programming. The structure of this block of code is consistent, but there’s that little part in the middle that’s always changing. Most of the time we just trudge through the code because we want to get our stuff done, clock out, then go home and drink beer.

C# 3.0 adds a nice feature called lambda expressions, which is mostly syntactic sugar for anonymous delegates. Using them along with continuation-passing style we can write some helper functions that make this type of code much easier to deal with, and more expressive and succinct. In Paint.NET I’m adding a static class called "Do" that will help out with my code:

(Please note that Paint.NET’s "Function" delegate has the type parameters reversed from .NET 3.5’s "Func" delegate. "Func" delcares them in the traditional functional or mathematical ordering, where "F x -> y" is equivalent to "y F(x)". So, my code uses the "y-x" order. I added "Function" before .NET 3.5 added "Func", so let’s not get on my case about the ordering … 🙂 )

public static class Do
{
    public static T TryCatch<T>(Function<T> actionFunction, Function<T, Exception> catchClause)
    {
        T returnVal;

        try
        {
            returnVal = actionFunction();
        }

        catch (Exception ex)
        {
            returnVal = catchClause(ex);
        }

        return returnVal;
    }
}

(Quick digression: You’ll note that I do not assign to returnVal at the beginning of the function. This is a pattern I use quite often, because the C# compiler always does analysis to ensure a variable is assigned to before being used. This lets me make sure I always assign a meaningful value, and don’t miss the assignment in any of my branches or clauses. If I were to immediately assign "null", for instance, but then I forgot to assign a meaningful value to it in some if/else branch, then that error would go undetected.)

Once we have this utility function, the first code snippet simplifies to the following:

foreach (string fileName in Do.TryCatch(() => Directory.GetFiles(…), ex => new string[0]))
{
    … do some processing on this file …
}

Voila 🙂 I’m actually using this code in the setup wizard, as it needs to get a list of files in a directory and then delete them. If the directory doesn’t exist then there’s really nothing to do, but it also isn’t an error, and having the try/catch around the call wreaks havoc on the simplicity of the code. This lets me express that much more succinctly.

There are other patterns you can use, such as passing lambdas for the finally clause, or passing lambdas for various exception types, or even returning the exception for more imperative style processing.

Advertisement

7 thoughts on “Continuation-Passing Style Simplifies Your C# Exception Handling Code

  1. virtualblackfox says:

    Two useful variants :

    public static T TryDefault(Function actionFunction, T defaultValue)
    {
    return TryCatch(actionFunction, v => defaultValue);
    }

    public static T TryDefault(Function actionFunction)
    {
    return TryCatch(actionFunction, v => default(T));
    }

    Theses versions are mostly interesting in C#2.0 where they avoid the “delegate() { return ; }” syntax.

  2. Rick Brewster says:

    virtualblackfox — Yes but one thing your first function misses out on is the delayed execution of computing ‘defaultValue’ that is made possible by using a delegate instead of supplying a value. What if ‘defaultValue’ is expensive to compute? Although, that’s not to say yours do not have value 🙂 If you already know the default value (it’s null, it’s a constant, you already computed it anyway, etc.), then of course there’s no reason to add the overhead of a delegate.

  3. Eddie Butt says:

    I have a question about the above example. Is it a manufactured example? You say you are using this in the setup program so I wonder.

    I can envision scenarios where this pattern simplifies things but in this case don’t we just want:

    if Directory.Exists(…)
    {
    filenames = Directory.GetFiles(…);

    etc.
    }

    In this case the exception is not really that exceptional. Directories come and go. Krystof says, “When a member throws an exception, its performance can be orders of magnitude slower.”

    http://blogs.msdn.com/kcwalina/archive/2005/03/16/396787.aspx

    Just wondering.

  4. Rick Brewster says:

    Eddie — this is not a manufactured example. Even if Directory.Exists() returns true, that result could be stale by the time you call Directory.GetFiles(). You may as well just call GetFiles() with a try/catch harness. I’m using this in areas where the performance in the “exceptional” case isn’t really a bother. I’m not using it for, say, rendering loops 🙂

Comments are closed.