How to use an Expression to set a nested property?

.net c# expression-trees reflection

Question

So I have some code that sets a property on an object. This code is from an internal validation class that we're using in unit tests. So the code may be supplied something like

private static void SetDeepValue(object targetObject, Expression<Func<string>> propertyToSet, object valueToSet)
        {
            var underlyingProperty = ((PropertyInfo)((MemberExpression)propertyToSet.Body).Member);
            underlyingProperty.SetValue(targetObject, valueToSet);
        }

This code gets used in a unit-test type environment, where we can then make calls like

foreach (string currentTestCaseValue in TestCaseSets)
{
     BusinessObject myCustomer = new BusinessObject();
     SetDeepValue(myCustomer, ()=>myCustomer.FirstName,currentTestCaseValue);
     ValidateBusinessRules(myCustomer);
}

(code simplified for brevity/complexity)

However, now, due to some refactorings, we are left with something like:

foreach (string currentTestCaseValue in TestCaseSets)
    {
         BusinessObject myCustomer = new BusinessObject();
         SetDeepValue(myCustomer, ()=>myCustomer.NameInfo.First,currentTestCaseValue);
         ValidateBusinessRules(myCustomer);
    }

When this code runs, we get the error:

Object does not match target type.

I suspect it is trying to call the First property on the BusinessObject, instead of the NameInfo. How can I modify my code to handle this 'nested' case?

1
8
3/16/2015 7:25:32 PM

Popular Answer

Here's how you would usually convert string "ColumnName1.ColumnName2" to a lambda expression x => x.ColumnName1.ColumnName2:

Expression<Func<T, object>> ForNestedProperty(string columnName)
{
    // x
    ParameterExpression param = Expression.Parameter(typeof(T), "x");

    // x.ColumnName1.ColumnName2
    Expression property = columnName.Split('.')
                                    .Aggregate<string, Expression>
                                    (param, (c, m) => Expression.Property(c, m));

    // x => x.ColumnName1.ColumnName2
    Expression<Func<T, object>> lambda = Expression.Lambda<Func<T, object>>(
        Expression.Convert(property, typeof(object)), param);
    return lambda;
}

(Copied from here)

6
3/16/2015 7:10:30 PM


Related Questions





Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow