Reading Properties of an Object with Expression Trees

.net c# expression-trees lambda

Question

I want to create a Lambda Expression for every Property of an Object that reads the value dynamically.

What I have so far:

var properties = typeof (TType).GetProperties().Where(p => p.CanRead);

foreach (var propertyInfo in properties)
{
    var getterMethodInfo = propertyInfo.GetGetMethod();

    var entity = Expression.Parameter(typeof (TType));

    var getterCall = Expression.Call(entity, getterMethodInfo);

    var lambda = Expression.Lambda(getterCall, entity);
    var expression = (Expression<Func<TType, "TypeOfProperty">>) lambda;
    var functionThatGetsValue = expression.Compile();
}

The code Works well when i call functionThatGetsValue as long as "TypeOfProperty" is hardcoded. I know that I can't pass the "TypeOfPoperty" dynamically. What can I do to achive my goal?

Accepted Answer

Assuming that you're happy with a Func<TType, object> delegate (as per the comments above), you can use Expression.Convert to achieve that:

var properties = typeof(TType).GetProperties().Where(p => p.CanRead);

foreach (var propertyInfo in properties)
{
    MethodInfo getterMethodInfo = propertyInfo.GetGetMethod();
    ParameterExpression entity = Expression.Parameter(typeof(TType));
    MethodCallExpression getterCall = Expression.Call(entity, getterMethodInfo);

    UnaryExpression castToObject = Expression.Convert(getterCall, typeof(object));
    LambdaExpression lambda = Expression.Lambda(castToObject, entity);

    var functionThatGetsValue = (Func<TType, object>)lambda.Compile();
}

Popular Answer

After hours of googling found the answer here. I've added the snippets from the blog post as it might help others having the same troubles:

public static class PropertyInfoExtensions
{
    public static Func<T, object> GetValueGetter<T>(this PropertyInfo propertyInfo)
    {
        if (typeof(T) != propertyInfo.DeclaringType)
        {
            throw new ArgumentException();
        }

        var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
        var property = Expression.Property(instance, propertyInfo);
        var convert = Expression.TypeAs(property, typeof(object));
        return (Func<T, object>)Expression.Lambda(convert, instance).Compile();
    }

    public static Action<T, object> GetValueSetter<T>(this PropertyInfo propertyInfo)
    {
        if (typeof(T) != propertyInfo.DeclaringType)
        {
            throw new ArgumentException();
        }

        var instance = Expression.Parameter(propertyInfo.DeclaringType, "i");
        var argument = Expression.Parameter(typeof(object), "a");
        var setterCall = Expression.Call(
            instance,
            propertyInfo.GetSetMethod(),
            Expression.Convert(argument, propertyInfo.PropertyType));
        return (Action<T, object>)Expression.Lambda(setterCall, instance, argument).Compile();
    }
}


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why