String-less ArgumentNullException

December 9, 2007

tags: ,
3 comments

The post I wrote yesterday about Expression Trees, and Jafar Husain’s work, have inspired me to find some more cool usages for this feature. Consider this code:

public class PersonRepository { public void Add(Person person, Context context) { if (person == null) throw new ArgumentNullException("person"); if (context == null) throw new ArgumentNullException("context"); //...Do the actual stuff } }

The main annoying thing about this code is having to write the parameter as a string, which might tackle refactoring of this method. Anyway, nobody likes too many strings in his code, right? Well, with Expression Trees and Extension Methods we can have this:

public void Add(Person person, Context context) { person.AssertNotNull( () => person ); context.AssertNotNull( () => context ); //...Do the actual stuff }

You will note that the code is shorter and contains no strings. We can achieve this by writing the following extension method:

1 public static class AssertionExtensions 2 { 3 public static void AssertNotNull<T>(this T value, Expression<Func<T>> paramNameExpr) 4 { 5 string paramSymbol = ((MemberExpression)paramNameExpr.Body).Member.Name; 6 7 if (value == null) 8 throw new ArgumentNullException(paramSymbol); 9 } 10 }

This method accepts our value, and a lambda expression. The lambda expression should be a method that accepts nothing, and returns a value of the same type. “()=>person” is exactly that. From the lambda, we extract the name of the parameter to put in the exception message.

Now, some of you might wonder why I’m casting to MemberExpression in line 5 here. Isn’t “()=>person” a ConstantExpression? There is no class here whose member is “person”! Well, actually, there is. since ()=>person is just a shortcut for an anonymous method, an anonymous class is created behind the scenes to support the fact that we are referencing a variable from an outer scope in the PersonRepository.Add method. This is the class whose member we’re accessing.

I definitely like this syntax. If only it weren’t so slow to build the expressions…

Add comment
facebook linkedin twitter email

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

3 comments

  1. עומר ון קלוטןDecember 9, 2007 ב 22:45

    The danger in posting this kind of code is that some day, someone will actually go ahead and use it, regardless of your caveat…

    Reply
  2. doronyDecember 9, 2007 ב 23:08

    Well, maybe some day the expression creation performance will be improved enough for it to be worth it 🙂
    Anyway, I think I will still use the extension method part, but it will have to be person.AssertNotNull(“person”) for now.

    Reply
  3. Ben CookeFebruary 19, 2008 ב 18:09

    Am I right in thinking that you’re also forcing the compiler to create a closure on your arguments here?

    This means that you’ll have an instantiation overhead of the closure on every call to your method, and all references to those formerly-local variables become object member lookups, which are also more expensive because they involve indirection.

    Also, if you actually do ultimately return any anonymous delegates with references into the parent scope your delegates will end up holding references to all of your arguments, regardless of whether the delegates actually use the arguments. If one of your arguments is a particularly large object, you’ll prevent it from getting collected until your delegate goes out of scope, which if your delegate is being used as some sort of event handler or callback might not be until your program terminates.

    Basically, introducing this “should never happen” assertion impacts the performance of the rest of the method in several unexpected ways. I’d say that the developer convenience here is outweighed by the performance implications.

    Reply