诀窍是:这种形式的任何表达方式…
obj => obj.A.B.C // etc.
…实际上只是一堆嵌套
Memberexpression对象。
首先,您必须:
Memberexpression: obj.A.B.Cexpression: obj.A.B // MemberexpressionMember:C
评估
expression上面 _的
Memberexpression_为您提供:
Memberexpression: obj.A.Bexpression: obj.A // MemberexpressionMember:B
最后,以上 这 (在“顶部”),你必须:
Memberexpression: obj.Aexpression: obj // note: not a MemberexpressionMember:A
因此,似乎很明显,解决此问题的方法是通过检查up
的
expression属性,
Memberexpression直到不再成为a本身为止
Memberexpression。
更新 :看来您的问题有一个额外的旋转。可能您有一些lambda 看起来 像
Func<T, int>…
p => p.Age
…但 实际上是 一个
Func<T, object>; 在这种情况下,编译器会将上面的表达式转换为:
p => Convert(p.Age)
实际上,针对此问题进行调整并不像看起来那样困难。查看我的更新代码,了解一种处理它的方法。请注意,通过抽象化用于
Memberexpression脱离其自身方法(
TryFindMemberexpression)的代码,该方法可以使
GetFullPropertyName方法保持相当干净,并允许您将来添加其他检查-
如果也许您发现自己面对的是 新 环境,最初并没有考虑-无需花费太多代码。
举例说明:这段代码对我有用。
// pre adjusted to prevent horizontal overflowstatic string GetFullPropertyName<T, TProperty>(expression<Func<T, TProperty>> exp){ Memberexpression memberExp; if (!TryFindMemberexpression(exp.Body, out memberExp)) return string.Empty; var memberNames = new Stack<string>(); do { memberNames.Push(memberExp.Member.Name); } while (TryFindMemberexpression(memberExp.expression, out memberExp)); return string.Join(".", memberNames.ToArray());}// pre adjusted to prevent horizontal overflowprivate static bool TryFindMemberexpression(expression exp, out Memberexpression memberExp){ memberExp = exp as Memberexpression; if (memberExp != null) { // heyo! that was easy enough return true; } // if the compiler created an automatic conversion, // it'll look something like... // obj => Convert(obj.Property) [e.g., int -> object] // OR: // obj => ConvertChecked(obj.Property) [e.g., int -> long] // ...which are the cases checked in IsConversion if (IsConversion(exp) && exp is Unaryexpression) { memberExp = ((Unaryexpression)exp).Operand as Memberexpression; if (memberExp != null) { return true; } } return false;}private static bool IsConversion(expression exp){ return ( exp.NodeType == expressionType.Convert || exp.NodeType == expressionType.ConvertChecked );}用法:
expression<Func<Person, string>> simpleExp = p => p.FirstName;expression<Func<Person, string>> complexExp = p => p.Address.State.Abbreviation;expression<Func<Person, object>> ageExp = p => p.Age;Console.WriteLine(GetFullPropertyName(simpleExp));Console.WriteLine(GetFullPropertyName(complexExp));Console.WriteLine(GetFullPropertyName(ageExp));
输出:
FirstNameAddress.State.AbbreviationAge



