扁平化Lambda表达式以访问集合属性成员名称



给定以下类

public class Person
{
    public string Name { get; }
    public List<Person> Friends { get; }
}

我正在寻找一种方法来获得以下字符串"朋友。名称",当使用表达式>时。

下面是我想要做的伪代码:

Expression<Func<Person,string>> exp = x => x.Friends.Name

由于显而易见的原因无法编译。

我怎么才能做到呢?即使你没有代码,一个通用的方法也可以做到这一点,因为我在这方面缺乏灵感。

谢谢

你不能得到你想要的,使用这种类型的表达式:

Expression<Func<Person,string>>

,因为PersonFriends的集合。实际上,Func的返回类型在这里并不重要。

    static string GetPath(Expression<Func<Person, object>> expr)
    {
        var selectMethodCall = (MethodCallExpression)expr.Body;
        var collectionProperty = (MemberExpression)selectMethodCall.Arguments[0];
        var collectionItemSelector = (LambdaExpression)selectMethodCall.Arguments[1];
        var collectionItemProperty = (MemberExpression)collectionItemSelector.Body;
        return $"{collectionProperty.Member.Name}.{collectionItemProperty.Member.Name}";
    }

用法:

var path = GetPath(_ => _.Friends.Select(f => f.Name)); // Friends.Name

但这是一个相当简单的情况下,而在我看来,你正在做的事情像Include方法从实体框架。
所以,如果你想解析更复杂的表达式,像这样:

_ => _.Friends.Select(f => f.Children.Select(c => c.Age))

您需要以更通用的方式来探索表达式

假设如下所示,您可以获得如下路径:

Expression<Func<Person, string>> exp = x => x.Name; 
var lambdaBody = exp.Body;
if(lambdaBody.NodeType == ExpressionType.MemberAccess)
{
    var memberExpression = lambdaBody as MemberExpression;
    Console.WriteLine(memberExpression.ToString());
}
输出:

x.Name

最新更新