String-less ArgumentNullException
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...