Reading Properties of an Object with Expression Trees
12,315
Solution 1
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();
}
Solution 2
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();
}
}
Author by
gsharp
If you like StackOverflow favorites and wish improvements read my meta post and vote up.
Updated on July 18, 2022Comments
-
gsharp almost 2 years
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?-
LukeH almost 11 yearsWhat is your goal? You say you want to create a lambda expression; do you only need the compiled delegate (
functionThatGetsValue
), or do you need the intermediate expression tree too (expression
)? -
gsharp almost 11 years@LukeH, just the compiled delegate. thanks. (My goal is to iterate through a list of objects, and read all the values from the properties. To gain a bit of performance I want to do it this way instead of using reflection)
-
Oleh Nechytailo almost 11 yearsWhen I tried to achieve similar result I ended with returning Func<Type, Object> and casting return value to specific property type on caller`s side.
-
LukeH almost 11 yearsI agree with Nechytailo that you'll probably need to create your delegate as a
Func<TType,object>
, invoke it, and then cast the result to its specific type (if necessary). -
gsharp almost 11 yearsI would be fine with that, but the problem is that from "getterMethodInfo" it takes the actualy type and when I try to cast the lambda to Func<TType,object> it can't be casted.
-