正在评估 select 投影

Evaluating select projection

是否可以在某个时候评估 select 投影以获得正在 selected 的属性列表?

例如,如果我有以下 class:

public class Example()
{
    public string Aaa { get; set; }

    public int Bbb { get; set; }

    public string Ccc { get; set; }
}

和以下 select 投影:

Expression<Func<Example, Example>> select = x => new Example { Aaa= x.Aaa, Ccc = x.Ccc };

是否可以解释 select 投影以获得与 var result = new List<string> { "Aaa", "Ccc" }; 一致的结果?

执行此类操作的最佳方法是使用 ExpressionVisitor

这是一个例子:

public class MyMemberExpressionVisitor : ExpressionVisitor
{
    protected override Expression VisitMember(MemberExpression node)
    {
        if (node.Member.MemberType == MemberTypes.Property // is a property
            && node.Expression.NodeType == ExpressionType.Parameter // is from a parameter expression
            && Members.All(s => s != node.Member.Name)) // avoids duplicates
        {
            Members.Add(node.Member.Name);
        }

        return base.VisitMember(node);
    }

    public List<string> Members { get; set; } = new List<string>();
}

那么你可以这样使用它:

// Complex expressions work too!
Example outsideExample = new Example();
Expression<Func<Example, Example>> expression = x => new Example(
    x.Aaa + outsideExample.Bbb,
    x.Ccc + x.Aaa.Length);

var myVisitor = new MemberExpressionVisitor();
myVisitor.Visit(expression);
Console.WriteLine(string.Join(", ", myVisitor.Members)); // This should print out "Aaa, Ccc"

您可以访问 How to: Implement an Expression Tree Visitor 了解更多关于如何实施的信息。

要查找该表达式中的所有 属性 表达式,您可以使用 ExpressionVisitor 检查给定表达式中的所有 Expression 实例并查看哪些是 属性 访问,以及 属性 正在访问的内容:

internal class PropertySearchVisitor : ExpressionVisitor
{
    private List<MemberInfo> properties = new List<MemberInfo>();
    public IEnumerable<MemberInfo> Properties => properties;
    protected override Expression VisitMember(MemberExpression node)
    {
        if (node?.Member?.MemberType == MemberTypes.Property)
            properties.Add(node.Member);
        return base.VisitMember(node);
    }
}

一旦你有了它,你就可以编写一个方法来访问给定的表达式和 return 该表达式的属性(或 属性 名称):

public static IEnumerable<MemberInfo> GetProperties(this Expression expression)
{
    var visitor = new PropertySearchVisitor();
    visitor.Visit(expression);
    return visitor.Properties;
}
public static IEnumerable<string> GetPropertyNames(this Expression expression)
{
    var visitor = new PropertySearchVisitor();
    visitor.Visit(expression);
    return visitor.Properties.Select(property => property.Name);
}