我正试图编写一个扩展方法来从给定的LambdaExpression
中检索属性路径。
我希望能够像一样称呼它
var路径=((事件e(=>e.Address.City.Name(.ToChainedPath((;
它将返回Address.City.Name
作为由.
分隔的string
。
目前我的分机看起来像这个
public static string ToChainedPath<TSource, TProperty>(this Expression<Func<TSource, TProperty>> expr, char separator = '.')
{
MemberExpression me;
switch (expr.Body.NodeType)
{
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
var ue = expr.Body as UnaryExpression;
me = ue?.Operand as MemberExpression;
break;
default:
me = expr.Body as MemberExpression;
break;
}
var propertyNames = new List<string>();
while (me != null)
{
propertyNames.Add(me.Member.Name);
me = me.Expression as MemberExpression;
}
propertyNames.Reverse();
return string.Join(separator, propertyNames);
}
像一样使用时效果良好
Expression<Func<Event, string>> expression = e => e.Address.City.Name;
var propertyChain = expression.ToChainedPath();
但这不适用于我想要的,因为(Event e) => e.Address.City.Name
是Func<Event, string>
而不是Expression<Func<Event,string>>
。我已经尝试将Func
转换为Expression
,但到目前为止没有任何帮助。
我还将扩展更改为扩展Func
而不是Expression
,但随后我松开了Body
。
这样做可能吗?
lambda表达式本身没有类型(请参阅规范(,因此如果只执行以下操作,编译器将不知道在哪里可以找到ToChainedPath
:
((Event e) => e.Address.City.Name).ToChainedPath();
您没有给它任何关于lambda表达式应该转换为什么的类型信息(委托类型?表达式类型?(。因此,这种确切的语法是不可能的。
可以提供类型信息的另一种方法是使用方法参数。
EnclosingClass.GetChainedPath(e => e.Address.City.Name);
如果编译器能够解析GetChainedPath
是什么,它将知道它有一个类型为Expression<Func<Event, string>>
:的参数
public static string GetChainedPath<TSource, TProperty>(Expression<Func<TSource, TProperty>> expr, char separator = '.')
因此它知道lambda应该转换成什么类型
如果你想让它更加简洁(省略EnclosingClass.
(,你可以为GetChainedPath
做一个using static
。
using static YourNamespace.EnclosingClass;