Oooh, pretty code
Thursday, January 29, 2009 11:45:51 PM (Pacific Standard Time, UTC-08:00) ( CMPT 376 | Random Stuff | Tips | Wild Ideas )
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
Arg
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:
MemberExpression
() => foo
MemberInfo
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.
object/string
NotNullOrEmpty
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
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.
RSS
Sign In