诀窍是:这种形式的任何表达方式…
obj => obj.A.B.C // etc.
…实际上只是一堆嵌套MemberExpression
对象。
首先,您必须:
MemberExpression: obj.A.B.C
Expression: obj.A.B // MemberExpression
Member: C
评估Expression
上面 _的MemberExpression
_为您提供:
MemberExpression: obj.A.B
Expression: obj.A // MemberExpression
Member: B
最后,以上 这 (在“顶部”),你必须:
MemberExpression: obj.A
Expression: obj // note: not a MemberExpression
Member: A
因此,似乎很明显,解决此问题的方法是通过检查up 的Expression
属性,MemberExpression
直到不再成为a本身为止MemberExpression
。
:看来您的问题有一个额外的旋转。可能您有一些lambda 看起来 像Func<T, int>
…
p => p.Age
…但 实际上是 一个Func<T, object>
; 在这种情况下,编译器会将上面的表达式转换为:
p => Convert(p.Age)
实际上,针对此问题进行调整并不像看起来那样困难。查看我的更新代码,了解一种处理它的方法。请注意,通过抽象化用于MemberExpression
脱离其自身方法(TryFindMemberExpression
)的代码,该方法可以使GetFullPropertyName
方法保持相当干净,并允许您将来添加其他检查- 如果也许您发现自己面对的是 新 环境,最初并没有考虑-无需花费太多代码。
// code adjusted to prevent horizontal overflow
static 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());
}
// code adjusted to prevent horizontal overflow
private 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));
输出:
FirstName
Address.State.Abbreviation
Age