Embedding LINQ Expression for a method call

Consider evaluating an Expression at runtime, for some lame reason you had to call ToLower() on a string object, and create a predicate out of it. Using LINQ expressions simplifies the task of doing these things. Simply embed the custom Expression that would evaluate against the LINQ extension methods. Below is a sample MethodCallExpression to embed a ToLower() method inside a LINQ query,

private static MethodCallExpression GetToLowerMethodCallExpression(Expression memExp)
{
    var tolowerMethod = typeof(string).GetMethods().Where(m => m.Name == "ToLower").FirstOrDefault();
    var toLowerMethodCall = Expression.Call(
        memExp,
        tolowerMethod,
        new Expression[0]);
    return toLowerMethodCall;
}

Lets take a simple scenario, we would write a custom Expression (e) => some lambda functor, that would evaluate against a Contains predicate. We first would right down a normal functor that would return the value of a property by using a PropertyDescriptor,

Func<string, object> recordFunc = (columnName) =>
{
    var pd = properties.Find(columnName, false);
    return pd.GetValue(person1);
};

Since we cannot embed a full method inside an expression we split that into a Functor lambda, and then use that as a single expression given below,

Expression<Func<Person, bool>> e = (p) => p.Age1 == (int)recordFunc("Age2");

C# compiler generates a sequence of Expression calls to the lambda recordFunc (take a look in reflector with the compiled exe),

       Expression<Func<Person, bool>> e = Expression.Lambda<Func<Person, bool>>(Expression.Equal(Expression.Property(CS$0$0000 = Expression.Parameter(typeof(Person), "p"), (MethodInfo) methodof(Person.get_Age1)), Expression.Convert(Expression.Invoke(Expression.Constant(recordFunc), new Expression[] { Expression.Constant("Age2", typeof(string)) }), typeof(int))), new ParameterExpression[] { CS$0$0000 });

If we split this above expression into more meaningful method call, it should be as below,

public static LambdaExpression Contains(this object source, string propertyName, string propertyName2, Expression<Func<string, object>> recordFunctor)
{
    var type = source.GetType();
    var paramExp = Expression.Parameter(type, type.Name);
    var member = Expression.PropertyOrField(paramExp, propertyName);
    var member2 = Expression.PropertyOrField(paramExp, propertyName2);
    var convertedExp = Expression.Convert(Expression.Invoke(Expression.Constant(recordFunctor), new Expression[] { Expression.Constant(propertyName2, typeof(string)) }), member.Type);
    var binaryExp = Expression.Equal(member, convertedExp);
    var lambda = Expression.Lambda(binaryExp, paramExp);
    return lambda;
}

We can then use the above Contains extension method to embed a normal expression into LINQ predicate syntax or any LINQ extension method that requires a BinaryExpression to execute.

Download the sample here.

-Fahad

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: