I’m trying to create expressions to access either fields or properties in a nested structure.
I managed to create both getters and setters (as lambda expressions) for fields and properties on a flat object. It works like so:
Delegate getter = getGetterExpression(objectType,"PropertyOrFieldName").Compile();
Delegate setter = getSetterExpression(objectType,"PropertyorFieldName").Compile();
I found this post (Marc Gravells answer) using a custom expression visitor to "chain" those lambda expressions to access nested objects. Is this the right way to do this (by chaining lambda expressions), if you have some deep (dynamic) nesting like the following example code? Or is there a more efficient way to achieve this?
// 'regular' C# Code
obj.PropA.FieldB.FieldC.PropD = "Hello World";
// targeted 'expression approach'
Delegate setter = GetPathSetterLambda(obj.GetType(), "PropA.FieldB.FieldC.PropD").Compile();
setter.DynamicInvoke(obj, "Hello World!");
The getters and setters are created like this:
private static LambdaExpression getSetterExpression(Type objectType, string fieldOrPropertyName)
{
ParameterExpression parameterExpression = Expression.Parameter(objectType);
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, fieldOrPropertyName);
ParameterExpression valueParameterExpression = Expression.Parameter(memberExpression.Type);
BinaryExpression assignExpression = Expression.Assign(memberExpression, valueParameterExpression);
Type setterType = typeof(Action<,>).MakeGenericType(objectType, memberExpression.Type);
return Expression.Lambda(setterType, assignExpression, parameterExpression, valueParameterExpression);
}
private static LambdaExpression getGetterExpression(Type objectType, string fieldOrPropertyName)
{
ParameterExpression parameterExpression = Expression.Parameter(objectType);
MemberExpression memberExpression = Expression.PropertyOrField(parameterExpression, fieldOrPropertyName);
Type getterType = typeof(Func<,>).MakeGenericType(objectType, memberExpression.Type);
return Expression.Lambda(getterType, memberExpression, parameterExpression);
}
I’m trying to do this mostly to improve the performance compared to using reflection.