Magique, le mot n'est pas de trop pour définir cette astuce. En utilisant les Expression Trees, les types anonymes, et les extension methods, tous 3 apportés par le C#3 pour permettre à LINQ d'exister, voici un morceau de code qui vous permet de remplacer ce genre de code :

public void Toto(Foo foo, Bar bar)
{
    if (foo == null)
        throw new ArgumentNullException("foo");

    if (bar == null)
        throw new ArgumentNullException("bar");
}

Par :

public void Toto(Foo foo, Bar bar)
{
    new { foo, bar }.CheckNotNull();
}

Comment réussir un tel prodige? Grâce à ça :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;

public static class Extensions
{
    public static void CheckNotNull(this T container) where T : class
    {
        if (container == null)
        throw new ArgumentNullException("container");

        NullChecker.Check(container);
    }
    
    private static class NullChecker where T : class
    {
        private static readonly Func nullSeeker;
        
        static NullChecker()
        {
            Expression body = Expression.Constant(null, typeof(string));
            var param = Expression.Parameter(typeof(T), "obj");
            
            foreach (PropertyInfo property in typeof(T).GetProperties())
            {
                Type propType = property.PropertyType;
                
                if (propType.IsValueType && Nullable.GetUnderlyingType(propType) == null)
                    continue;
                    
                body = Expression.Condition(
                    Expression.Equal(
                        Expression.Property(param, property),
                        Expression.Constant(null, propType)),
                    Expression.Constant(property.Name, typeof(string)),
                    body);
            }

            nullSeeker = Expression.Lambda>(body, param).Compile();
        }

        internal static void Check(T item)
        {
            string nullArg = nullSeeker(item);
        
            if (!string.IsNullOrEmpty(nullArg))
                throw new ArgumentNullException(nullArg);
        }
    }
}

Sur le principe, c'est relativement "simple": On crée un type anonyme. Dans l'extension method, on va statiquement énumérer les arguments du constructeur du type de l'extension method, puis récupérer leur type et leur nom. On va ensuite itérer sur ces arguments pour créer un arbre d'expression dans lequel on va tester si le paramètre est une référence ou un ValueType, puis tester s'il est null. On compile l'arbre sous forme de delegate, et si celui-ci renvoie un string, c'est que l'argument dont le nom est renvoyé est null.

Ce qu'il y a de bien, c'est qu'on élimine le risque de se tromper dans l'écriture du nom du paramètre de ArgumentNullException. (A pondérer toutefois, car un outil comme Resharper par exemple permet de créer un template de code intelligent qui va utiliser automatiquement le nom du paramètre)

En négatif (ça serait trop facile sinon): la syntaxe un peu déroutante, et l'impact sur les performances. J'ai réalisé un petit benchmark où j'appelle 2 fonctions1 million de fois:

class Program
{
    private const int iterations = 10000000;

    static void Main(string[] args)
    {
        Stopwatch sw = new Stopwatch();

        Console.Write("Normal Test : ");

        sw.Start();

        for (int i = 0; i < iterations; i++)
        {
            using (Stream stream = new MemoryStream())
                NormalTest("Foo", "Bar", stream);
        }

        sw.Stop();

        Console.Write(" " + sw.ElapsedMilliseconds);

        sw.Reset();

        Console.WriteLine();
        
        Console.Write("Magic Test : ");

        sw.Start();

        for (int i = 0; i < iterations; i++)
        {
            using (Stream stream = new MemoryStream())
                MagicTest("Foo", "Bar", stream);
        }

        sw.Stop();

        Console.Write(" " + sw.ElapsedMilliseconds);

        Console.Read();
    }

    private static void NormalTest(string text, string text2, Stream stream)
    {
        if (text == null)
            throw new ArgumentNullException("text");

        if (text2 == null)
            throw new ArgumentNullException("text2");

        if (stream == null)
            throw new ArgumentNullException("stream");

        UnicodeEncoding utf = new UnicodeEncoding();
        byte[] b1 = utf.GetBytes(text);

        stream.Write(b1, 0, b1.Length);

        byte[] b2 = utf.GetBytes(text2);
        stream.Write(b2, 0, b2.Length);
    }

    private static void MagicTest(string text, string text2, Stream stream)
    {
        new { text, text2, stream }.CheckNotNull();

        UnicodeEncoding utf = new UnicodeEncoding();
        byte[] b1 = utf.GetBytes(text);

        stream.Write(b1, 0, b1.Length);

        byte[] b2 = utf.GetBytes(text2);
        stream.Write(b2, 0, b2.Length);
    }
}

Résultat des courses: environ 5350ms pour la première fonction, contre environ 6280ms pour la deuxième. Je ne suis pas sûr que le benchmark soit des plus adéquats, mais ça reste à considérer dans le cas d'applications critiques où ça peut avoir un impact significatif.

A noter également que l'on peut parvenir à du code de vérification de ce genre, mais beaucoup plus lisible néanmoins, et fonctionnant à plus grande échelle, grâce aux Code Contracts, qui sera en plus natif en .NET 4.0.

En tout cas, je dois bien avouer que je trouve ça vraiment impressionant ce genre de code. Il serait vraiment grand temps que je me penche un peu plus sur tout ça (notamment les arbres d'expression), car tout cela est vraiment très intéressant!