Учитывая выражение лямбда-члена Member Access, преобразуйте его в определенное строковое представление с полным доступом
Учитывая
Expression<Func<T, object>>
(например, x = > x.Prop1.SubProp), я хочу создать строку "Prop1.SubProp" настолько, насколько это необходимо.
В случае единого доступа (например, x = > x.Prop1) я могу легко сделать это с помощью
MemberExpression body = (expression.Body.NodeType == ExpressionType.Convert) ? (MemberExpression)((UnaryExpression)expression.Body).Operand : (MemberExpression)expression.Body;
return body.Member.Name;
Однако, если есть более глубокое вложение, например. x = > x.Prop1.SubProp1, это получает только самое глубоко вложенное имя, например. "SubProp1" вместо "Prop1.SubProp1"
Есть ли вообще доступ к полному пути свойств выражения лямбда?
Ответы
Ответ 1
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());
}
Ответ 2
Взгляните на мой ответ на этот вопрос.
В значительной степени то же, что и LukeH, с одной дополнительной функцией:
Если у вас есть тип, скажем, MyClass
, с свойством MyProperty
типа int
, вы можете написать это:
Expression<Func<MyClass, object>> e = x => x.MyProperty;
Здесь выражение e.Body
не является MemberExpression
, поэтому простой while (me != null) me = me.Expression as MemberExpression
не будет работать.
Решение должно дополнительно проверить, если оно UnaryExpression
с NodeType == Convert
или ConvertChecked
.
Могут быть другие сценарии для учета; но для простых цепочек выражений свойств этот подход работает очень хорошо.
Ответ 3
Вы можете использовать проект, который я создал для преобразования lambda в javascript: lambda2js
При использовании только свойств и индексаторов результат должен быть именно тем, что вам нужно.
Пример 1: путь одиночного свойства
Expression<Func<MyClass, object>> expr = x => x.Phone;
var js = expr.CompileToJavascript();
// returns: Phone
Пример 2: Путь с индексом строкового словаря
Expression<Func<MyClass, object>> expr = x => x.PhonesByName["Miguel"];
var js = expr.CompileToJavascript();
// returns: PhonesByName["Miguel"]
Пример 3: Сложный путь, содержащий индексы и несколько уровней
Expression<Func<MyClass, object>> expr = x => x.SomeProp["Miguel"].Subprop[0].A.B;
var js = expr.CompileToJavascript();
// returns: SomeProp["Miguel"].Subprop[0].A.B