I presented a method to retrieve the property name referenced by a lambda expression in a previous post.
Reader Jacek asked,
is there any way for nested property (eg. Studies.ID or Studies.Class.Name) to convert to string?
Nice question, and I tried to solve it.
Starting with a simple data model
public class Foo { public int FooID { get; set; } public string Name { get; set; } } public class Bar { public string Name { get; set; } public Foo BarFoo { get; set; } } public class Baz { public string Name { get; set; } public Bar BazBar { get; set; } }
we want to convert an expression such as b => b.BazBar.BarFoo.Name into its string representation.
public static string GetPropertyName(this LambdaExpression expression) {
First, we handle type casts, as in the original solution:
if (expression.Body is UnaryExpression) { UnaryExpression unex = (UnaryExpression)expression.Body; if (unex.NodeType == ExpressionType.Convert) { Expression ex = unex.Operand; MemberExpression mex = (MemberExpression)ex; return mex.Member.Name; } }
Keep a reference of the parameter, and set path (i.e. concatenated property names) to empty
MemberExpression memberExpression = (MemberExpression)expression.Body; MemberExpression memberExpressionOrg = memberExpression; string Path = "";
The sequence b.BazBar.BarFoo is stored as an expression of ExpressionType MemberAccess, which is an object of the non-public class System.Reflection.RuntimePropertyInfo (google), as the debugger tells us.
Since the class is not public, we need to access the Member property using reflection, in this case PropertyInfo.GetValue:
while (memberExpression.Expression.NodeType == ExpressionType.MemberAccess) { var propInfo = memberExpression.Expression .GetType().GetProperty("Member"); var propValue = propInfo.GetValue(memberExpression.Expression, null) as PropertyInfo; Path = propValue.Name + "." + Path; memberExpression = memberExpression.Expression as MemberExpression; } return Path + memberExpressionOrg.Member.Name; }
The variable Path stores the sequence of property names as we iterate through the expression tree. Finally, the last property name is added.
Using this code, the line
Console.WriteLine( ExpressionExtensions.GetPropertyName( (Expression<Func<Baz, string>>)(b => b.BazBar.BarFoo.Name)));
produces this output:
BazBar.BarFoo.Name
Pingback: Deployment Checks for Configuration Data « devioblog
Pingback: Retrieving the Attribute Names of CRM 2011 Entities « devioblog