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?
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With