C# 给定成员访问lambda表达式,将其转换为具有完全访问路径的特定字符串表示形式

C# 给定成员访问lambda表达式,将其转换为具有完全访问路径的特定字符串表示形式,c#,.net,linq,C#,.net,Linq,给予 Expression<Func<T, object>> 但是,如果存在更深的嵌套,例如x=>x.Prop1.subpop1,则只获取嵌套最深的名称,例如“subpop1”而不是“Prop1.subpop1” 是否仍然可以访问lambda表达式的完整属性路径?公共字符串GetPath(expression expr) public string GetPath<T>(Expression<Func<T, object>> exp

给予

Expression<Func<T, object>> 
但是,如果存在更深的嵌套,例如x=>x.Prop1.subpop1,则只获取嵌套最深的名称,例如“subpop1”而不是“Prop1.subpop1”

是否仍然可以访问lambda表达式的完整属性路径?

公共字符串GetPath(expression expr)
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());
}
{ var stack=新堆栈(); 请原谅我; 开关(expr.Body.NodeType) { 大小写表达式类型。转换: case ExpressionType.ConvertChecked: 变量ue=将主体表示为一元表达式; me=((ue!=null)?ue.Operand:null)作为MemberExpression; 打破 违约: me=将主体表示为成员表达式; 打破 } while(me!=null) { stack.Push(me.Member.Name); me=me.Expression作为MemberExpression; } 返回字符串.Join(“.”,stack.ToArray()); }
看看我的答案

与LukeH发布的内容大致相同,但有一个附加功能:

如果您有一个类型,例如,
MyClass
,其属性
MyProperty
的类型为
int
,您可以编写以下代码:

Expression<Func<MyClass, object>> e = x => x.MyProperty;
表达式e=x=>x.MyProperty;
这里的表达式
e.Body
不是
MemberExpression
,因此简单的
while(me!=null)me=me.MemberExpression作为MemberExpression
的表达式将不起作用

解决方案是使用
NodeType==Convert
ConvertChecked
另外检查它是否是
UnaryExpression


可能还有其他情况需要考虑;但是对于简单的属性表达式链,这种方法非常有效。

您可以使用我创建的项目将lambda转换为javascript:

当只使用属性和索引器时,结果应该正是您所需要的

示例1:单个属性路径

Expression<Func<MyClass, object>> expr = x => x.Phone;
var js = expr.CompileToJavascript();
// returns: Phone
表达式expr=x=>x.Phone;
var js=expr.CompileToJavascript();
//退货:电话
示例2:包含字符串字典索引器的路径

Expression<Func<MyClass, object>> expr = x => x.PhonesByName["Miguel"];
var js = expr.CompileToJavascript();
// returns: PhonesByName["Miguel"]
表达式expr=x=>x.PhonesByName[“Miguel”]; var js=expr.CompileToJavascript(); //返回: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
expr=x=>x.SomeProp[“Miguel”].subop[0].A.B;
var js=expr.CompileToJavascript();
//返回:SomeProp[“Miguel”].subop[0].A.B

看看MemberExpression.Expression。只要它们都是MemberExpression实例,就可以使用它递归遍历表达式树。我很难选择一个“可接受的答案”,两者都很好。如果有人看到这个问题,我建议大家看看LukeH和Dan Tao的答案。可能是重复的,我只是在编辑我的答案,以便在编辑你的答案时考虑到
Convert
/
ConvertChecked
。@LukeH:我能说什么?很明显,你知道自己在做什么;)你知道有没有一种干净的方法可以将数组访问保留为一个索引表达式而不是MemberCallExpression?+1:智者皆有同感!有一点:您不认为应该定义这个
GetPath(Expression-expr)
?否则,您几乎总是会遇到
Convert
/
ConvertChecked
场景——这仅仅是因为参数被不必要地强制转换。(或者我遗漏了什么?@Dan:是的,我同意。事实上,在编辑之前,我的签名是
GetPath(Expression expr)
。我将其更改为与问题中显示的表达式相匹配。我会让它保持原样,我想OP可以选择他们喜欢的签名-方法体中的代码在任何情况下都保持不变。知道如何修改它以使用包含索引(即方括号)运算符的表达式吗?
Expression<Func<MyClass, object>> expr = x => x.SomeProp["Miguel"].Subprop[0].A.B;
var js = expr.CompileToJavascript();
// returns: SomeProp["Miguel"].Subprop[0].A.B