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)

Awesomeness, in a box.

Thanks to Alex Tuteur for typing up the lyrics from our scribbles on paper, to Kyle Farnung for filiming, converting and posting the video, to Kristine Johnson for singing the epic win-ness, and to all the people who helped write the song!

STILL AROUND
By Andrew Nurse, Kristine Johnson, Alex Tuteur, Ben Butler, Kyle Farnung, Steven Truong (EXP), Adam Kiu, and William Hong

Internz: a triumph
I’m sending a lolcat: EPIC FAIL
It’s hard to understate procrastination
MICROSOFT INTERNS
We do nothing but read mail all day
For the good of all of us
Except for the FTEs
But there’s no sense crying over broken compiles
You just keep on building, it’ll work in awhile
And the coding gets done
And you make a bad pun
For the interns who are
STILL AROUND

I’m not really working
I’m reading Internz all day long
Even though I didn’t meet commitments
And now it’s review time
And it is my future on the line
As I leave it sucks because
I was so happy right here
Now it’s time to leave and I am packing my bag
To go back to my school and deal with the jet lag
So I’m GLaD that I’ve turned
Think of all the cash we’ve earned
As the interns who are
STILL AROUND

I’m going to leave now
I guess you prefer to stay right here
Maybe I’ll find someone else to work for
Maybe at Google
THAT WAS A JOKE, HAHA, FAT CHANCE
Anyway this lolcat’s great
It’s so amusing and fun
Look at me still coding when there’s packing to do
When I look out there it makes me GLaD I’m not you
I’ve got all my boxes done
Now it’s time for me to run
Bye bye interns who are
STILL AROUND

I can’t believe you are all
STILL AROUND
I’m done with coding and you’re
STILL AROUND
I’m leaving now and you are
STILL AROUND
While I’m at school you’ll be
STILL AROUND
And when I’m back here you’ll be
STILL AROUND
STILL AROUND
STILL AROUND

Test Post from Windows Live Writer

Just writing a test post from Windows Live Writer. Look for a future, more detailed post about it!

Technorati Tags:

Here's a map!

Map image

ooo...fancy...