Udostępnij za pośrednictwem


ArgumentNullException and refactoring

I hate using strings to represent program elements!  One of the big problems is that it hinders automated refactoring.  Strings don’t have any semantic meaning, so refactoring tools don’t know which references to the string need to be updated.

 

While playing with expression trees, a while ago I came up with this:

 public static class Argument{    public static void NotNull(object value, Expression<Func<Func<object>>> arg)    {        if (value == null)        {            var body1 = (Expression<Func<object>>)arg.Body;            var body2 = (MemberExpression)body1.Body;            throw new ArgumentNullException(body2.Member.Name);        }    }}

 

You can use this for argument validation like this:

 static void Main(string[] args){    Argument.NotNull(args, () => () => args);}

 

This looks a little strange, but has some interesting properties:

  1. There are no strings, which means that refactoring tools “Just Work” and update all references.
  2. The majority of the reflection code happens only in the exception code, which means that this has significantly better performance than my first attempt (which took just an “Expression<Func<object>>”

On the other hand it has some drawbacks too:

  1. The calling side looks a little strange with “() => () =>'”
  2. Using this approach will lead to a LOT of compiler generated display classes to store the parameter references.

I’m not sure I would use this in production code, but it was an interesting exercise to come up with a way of validating parameters that doesn’t involve strings.

 

What do you think?

Comments

  • Anonymous
    October 27, 2008
    We use a similar trick for our INotifyPropertyChanged implementations for mostly the same reasons (refactoring, plus it's so easy to mistype a property name when it's a string, and the compiler doesn't check).

  • Anonymous
    October 27, 2008
    If you're willing to take a small performance hit, you can skip the first 'value' argument, and replace 'value == null' with 'arg.Compile()()() == null'.  This results in a cleaner usage / DRY: Argument.NotNull(() => () => args); The perf hit is the Compile() call.  For me, avoiding the bug where I copy/paste one call to create other calls, and forget to replace one of the parameters is worth the tradeoff most of the time. I think I'd keep both as overloads (sharing some implementation).  I'd use the 1-parameter version until performance analysis revealed the bottleneck in my code, and there switch to the other. Kevin knows all of this, of course: I'm trying to be useful to the other readers.

  • Anonymous
    October 29, 2008
    The comment has been removed

  • Anonymous
    November 09, 2008
    It would be nice (and much easier than the suggested code) if the compiler would support a nameof operator similar to the typeof operator. static void Main(string[] args) {    if (arges == null)      throw new ArgumentNullException(nameof(args)); } The nameof operator should support as many types of identifiers as possible and return the name of the identifier as a string.