user1765603 user1765603 - 1 month ago 6
C# Question

C# Generate Expression<Func<Foo, object>>

I am using a library containing a function which takes an expression parameter, x => x.Name.

Using reflection, I am trying to call this for each property of Foo. This means that I need to create an expression of type Expression<Func<Foo, object>> for each property.

I have been reading about expression trees, but nothing that covers this case.

foreach (var property in typeof(Foo).GetProperties())
{
ParameterExpression pe = Expression.Parameter(typeof(Foo), "x");
MemberExpression me = Expression.Property(pe, property.Name);

Expression<Func<Foo, object>> expression = ... // x => x.Name

Bar(expression, property.Name);
}





Solved:

foreach (var property in typeof(Foo).GetProperties())
{
ParameterExpression pe = Expression.Parameter(typeof(Foo), "x");
MemberExpression me = Expression.Property(pe, property.Name);

var expression = (Expression<Func<Foo, object>>)
Expression.Lambda(Expression.Convert(me, typeof(object)), pe);

Bar(expression, property.Name);
}

Answer

The problem is that you apparently do not know the type Foo at compile-time, otherwise you could simply create a lambda expression using the generic Expression.Lambda overload and be fine. There is a overload Expression.Lambda that will create a LambdaExpression and derives the type parameters from the expression you specified. This means, it will deduct it from the parameter expression and the member expression you use as body.

In both implementations, there is a catch, though. The return type object is a reference type. The properties may however return a value type (such as int), which requires casting. Normally, the compiler does that for you. In this case, you have to do that by yourself.

private IEnumerable<LambdaExpression> CreateExpressions(Type fooType)
{
    foreach (var property in fooType.GetProperties())
    {
        ParameterExpression pe = Expression.Parameter(fooType, "x");
        MemberExpression me = Expression.Property(pe, property.Name);

        yield return Expression.Lambda(Expression.Convert(me, typeef(object)), pe);
    }
}

If you know the type Foo at compile-time, you can simply add the generic parameter Func<Foo, object> to the Lambda method.

Comments