将给定的 属性-access 转换为链式字符串
Convert a given property-access to chained string
我正在尝试编写一个扩展方法来从给定的 LambdaExpression
.
中检索 属性 路径
我希望可以这样称呼它
var path = ((Event e) => e.Address.City.Name).ToChainedPath();
这将 return 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 表达式本身没有类型(参见 spec),因此编译器不知道在哪里可以找到 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;
我正在尝试编写一个扩展方法来从给定的 LambdaExpression
.
我希望可以这样称呼它
var path = ((Event e) => e.Address.City.Name).ToChainedPath();
这将 return 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 表达式本身没有类型(参见 spec),因此编译器不知道在哪里可以找到 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;