Given an
Expression<Func<T, object>>
(e.g. x => x.Prop1.SubProp), I want to create a string "Prop1.SubProp" for as deep as necessary.
In the case of a single access (e.g. x => x.Prop1), I can easily do this with:
MemberExpression body = (expression.Body.NodeType == ExpressionType.Convert) ? (MemberExpression)((UnaryExpression)expression.Body).Operand : (MemberExpression)expression.Body;
return body.Member.Name;
However, if there is deeper nesting, e.g. x => x.Prop1.SubProp1, this only gets the most deeply nested name, e.g. "SubProp1" instead of "Prop1.SubProp1"
Is there anyway to access the full property path of a lambda expression?
public string GetPath<T>(Expression<Func<T, object>> expr)
{
var stack = new Stack<string>();
MemberExpression me;
switch (expr.Body.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = expr.Body as UnaryExpression;
me = ((ue != null) ? ue.Operand : null) as MemberExpression;
break;
default:
me = expr.Body as MemberExpression;
break;
}
while (me != null)
{
stack.Push(me.Member.Name);
me = me.Expression as MemberExpression;
}
return string.Join(".", stack.ToArray());
}
GetPath<T, TProperty>(Expression<Func<T, TProperty>> expr)
? Otherwise you're nearly always going to run into that Convert
/ConvertChecked
scenario -- simply because the argument is cast unnecessarily. (Or am I missing something?) - Dan TaoGetPath<T,U>(Expression<Func<T,U>> expr)
. I changed it to match the expression shown in the question. I'll leave it as-is, and I suppose the OP can choose which signature they prefer - the code in the method body stays the same either way. - LukeH
Take a look at my answer to this question.
Pretty much the same as what LukeH posted, with one additional feature:
If you have a type, say, MyClass
, with a property MyProperty
of type int
, you could write this:
Expression<Func<MyClass, object>> e = x => x.MyProperty;
Here the expression e.Body
is not a MemberExpression
so the simple while (me != null) me = me.Expression as MemberExpression
won't work.
The solution is to check additionally if it's a UnaryExpression
with NodeType == Convert
or ConvertChecked
.
There may be other scenarios to account for; but for simple chains of property expressions, this approach works pretty well.
You can use a project I have created to convert lambda to javascript: lambda2js
When using only properties and indexers, the result should be exactly what you need.
Example 1: Single property path
Expression<Func<MyClass, object>> expr = x => x.Phone;
var js = expr.CompileToJavascript();
// returns: Phone
Example 2: Path containing indexer of a string dictionary
Expression<Func<MyClass, object>> expr = x => x.PhonesByName["Miguel"];
var js = expr.CompileToJavascript();
// returns: PhonesByName["Miguel"]
Example 3: Complex path containing indexers and multiple levels
Expression<Func<MyClass, object>> expr = x => x.SomeProp["Miguel"].Subprop[0].A.B;
var js = expr.CompileToJavascript();
// returns: SomeProp["Miguel"].Subprop[0].A.B