I remember looking through some of the included VS2008 samples (here), and there is quite a nice little DynamicQuery project demonstrating the ExpressionParser demo type. It wasn’t long until I started having a play with how we could take advantage of this in code.

The first step was to make a few modifications to the ExpressionParser type, namely changing access modifiers and removing the limitation on using a fixed list of types. Where do we make these changes? Well, first step, let’s make it public.

public class ExpressionParser
{
  // ...
}

Next, let’s remove the constraint on predefined types, within the ParseMemberAccess method:

Expression ParseMemberAccess(Type type, Expression instance)
{
  // ...
        switch (FindMethod(type, id, instance == null, args, out mb))
        {
            case 0:
                throw ParseError(errorPos, Res.NoApplicableMethod,
                    id, GetTypeName(type));
            case 1:
                MethodInfo method = (MethodInfo)mb;
                //if (!IsPredefinedType(method.DeclaringType)) // Comment out this line, and the next.
                    //throw ParseError(errorPos, Res.MethodsAreInaccessible, GetTypeName(method.DeclaringType));
                if (method.ReturnType == typeof(void))
                    throw ParseError(errorPos, Res.MethodIsVoid,
                        id, GetTypeName(method.DeclaringType));
                return Expression.Call(instance, (MethodInfo)method, args);
            default:
                throw ParseError(errorPos, Res.AmbiguousMethodInvocation,
                    id, GetTypeName(type));
        }
  // ...
}

Now we are in a position to start flexing our function musicles. But first, we need to understand how it all works.

ExpressionParser can take a string expression and convert it to an Expression, which we can in turn create a Delegate for, so given the expression “(a + b)”, if we know the operand types, and the return type, we can create a Delegate. Let’s see how:

var @params = new[] 
              { 
                Expression.Parameter(typeof(int), "a"),
                Expression.Parameter(typeof(int), "b")
              };
              
var parser = new ExpressionParser(@params, "(a + b)", null);
var @delegate = Expression.Lambda(parser.Parse(typeof(int)), @params).Compile();

With that small bit of code, we’ve created some parameter expressions, named to match the operands in our expression, and then we use the ExpressionParser to create an Expression instance that represents our string expression. The next step was to compile the Lamda of that expression into an executable Delegate.

The nice thing about the Delegate type, is that it is castable to Func<> instances and makes using the code easy to use. Our example above could be used as such:

Func<int, int, int> func = (Func<int, int, int>)@delegate;
int result = func(1, 2); // Result should be three.

The important thing which I hope you get, is that we’ve taken a simple string expression and converted it into a much more powerful Func<> delegate, which is strongly-typed.

To this end, I’ve started building a FunctionFactory type used to easily generate these Func<> instances, e.g.

public static class FunctionFactory
{
    private static Delegate CreateInternal(Type[] argumentTypes, Type returnType, string expression, string[] argumentNames = null)
    {
        if (argumentNames != null)
        {
            if (argumentTypes.Length != argumentNames.Length)
                throw new ArgumentException("The number of argument names does not equal the number of argument types.");
        }

        var @params = argumentTypes
            .Select((t, i) => (argumentNames == null)
                                  ? Expression.Parameter(t)
                                  : Expression.Parameter(t, argumentNames[i]))
            .ToArray();

        ExpressionParser parser = new ExpressionParser(@params, expression, null);

        var @delegate = Expression.Lambda(parser.Parse(returnType), @params).Compile();
        return @delegate;
    }

    public static Func<TReturn> Create<TReturn>(string expression, string[] argumentNames = null)
    {
        return (Func<TReturn>)CreateInternal(new Type[0], typeof(TReturn), expression, argumentNames);
    }

    public static Func<A, TReturn> Create<A, TReturn>(string expression, string[] argumentNames = null)
    {
        return (Func<A, TReturn>)CreateInternal(new[] { typeof(A) }, typeof(TReturn), expression, argumentNames);
    }

    public static Func<A, B, TReturn> Create<A, B, TReturn>(string expression, string[] argumentNames = null)
    {
        return (Func<A, B, TReturn>)CreateInternal(new[] { typeof(A), typeof(B) }, typeof(TReturn), expression, argumentNames);
    }
}

Now we can do some really cool stuff:

string expression = "(1 + 2)";
var func = FunctionFactory.Create<int>(expression);

int result = func(); // Result should be 3.

expression = "(a * b)";
var func2 = FunctionFactory.Create<int, int, int>(expression, new[] { "a", "b" });

int result = func2(10, 50); // Result should be 500.

We can even go a bit further and handle more complex objects, so if I have an example type, Person with an Age property, we can test against it:

expression = "(Age == 5)";
var func3 = FunctionFactory.Create<Person, bool>(expression);
bool isFive = func3(new Person { Age = 5 });

As you can see, the application of these types of expressions is quite endless. Personally I’ve now been able to introduce dynamic expressions into quite complex rule systems to allow for an additional dimension of flexibility.

Please find the demo project attached, it’s not as tidy as usual, but still fun to play with and extend.

FunctionFactory VS2010 Project

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)