Wild Ideas – Using lambdas to check arguments in C#

One of the most common checks I do is a simple null check on arguments being passed in to the methods I write.  I usually create a static class called “Arg” with the following methods (to help out):

public static class Arg {
    public static void NotNull(object value, string paramName) {
        if (value == null) {
            throw new ArgumentNullException(paramName);
        }
    }
    public static void NotNullOrEmpty(string value, string paramName) {
        if (String.IsNullOrEmpty(value)) {
            // ED: Error_StringArgumentNullOrEmpty is a key in my Visual Studio
            //  project's default string resources file (Properties/Resources.resx)
            throw new ArgumentException(
                String.Format(CultureInfo.CurrentCulture, 
                              Resources.Error_StringArgumentNullOrEmpty, 
                              paramName), 
                paramName);
        }
    }
}

Then, I can use it like this

public void Foo(string arg, object reallyLongArgumentName) {
    Arg.NotNullOrEmpty(arg, "arg");
    Arg.NotNull(reallyLongArgumentName, "reallyLongArgumentName");
}

I was recently playing with lambda expressions in C# and thought of a way to make this a little cooler.  The result is, I can rewrite the lines above like this:

public void Foo(string arg, object reallyLongArgumentName) {
    Arg.NotNullOrEmpty(() => arg);
    Arg.NotNull(() => reallyLongArgumentName);
}

The first obvious advantage is that for longer argument names, its more concise.  The second, is that I no longer have to worry about updating the strings representing the parameter names when I rename arguments, the Visual Studio Refactoring engine will take care of it for me.

Obviously, this is slower than the previous method since I’m diving into the lambda expression at runtime, but its cool.  But if I need the performance, I have a little Regular Expression I can run in Visual Studio to convert the lambda calls back to the string versions (and vice-versa)

How does it work? Well, the core of the code is a static helper in the Arg class

private static string GetParameterName<T>(Expression<Func<T>> paramExpr) {
    LambdaExpression lambda = paramExpr as LambdaExpression;
    Debug.Assert(lambda != null);
    MemberExpression paramRef = lambda.Body as MemberExpression;
    Debug.Assert(paramRef != null);

    // Get the parameter name
    string paramName = paramRef.Member.Name;
    return paramName;
}

Lines 2-5 dive through the Expression tree to find the MemberExpression that represents the parameter (i.e. "foo" in () => foo). Then, we pull out the MemberInfo for the parameter and check the name. With that method, the actual checker is easy:

public static void NotNull(Expression<Func<object>> paramExpr) {
    string paramName = GetParameterName(paramExpr);

    // Compile the lambda (to get the value)
    Func<object> compiledLambda = paramExpr.Compile();
    
    // Run the contract check
    NotNull(compiledLambda(), paramName);
}

Line 2 extracts the parameter name. Line 5 compiles the lambda into an actual function that will return the value of the parameter. Finally, Line 8 uses the value and the parameter name to call my original object/string version. The code for NotNullOrEmpty is nearly identical.

Anyway, if you're concerned about performance, stick to the overloads which take the parameter name directly. I’ve attached the code as a TXT file, just rename to C#, change the namespace as appropriate and enjoy

Arg.txt (3.93 KB)
Comments are closed.