【问题标题】:Traverse an expression tree and extract parameters遍历表达式树并提取参数
【发布时间】:2015-07-20 11:56:58
【问题描述】:

我正在编写一种映射工具。我有一个看起来像这样的方法(简化):

   public void RegisterMapping<TTarget, TSource>(string propertyName, 
                                                 Expression<Func<TSource, object>> memberMap)

memberMap 是一个表达式,用于定义如何将属性从 TSource 转换为 TTarget。对于业务逻辑,我需要从中提取对TSource 属性的所有引用。例如,来自

x => x.Customers.Where(c => c.Orders.Any())

我想得到Customers,并来自

x => x.FirstName + " " + x.LastName

FirstNameLastName(可以是 string[],PropertyInfo 很容易转换为)。

我该怎么做?我的第一种方法是手动遍历树,检查节点类型并根据节点类型检查不同的属性(例如,Operand 用于一元表达式,Arguments 用于函数调用)以确定其中任何一个是TSource。然后我发现了expression kind list 然后我放弃了——即使我只支持最常见的类型,它仍然需要做很多工作。然后我找到了ExpressionVisitor。它看起来更好,但是覆盖访问者方法仍然需要做很多工作,我想知道是否还有其他选择,使用可能更专业的框架,然后再花时间解决这个问题。

【问题讨论】:

标签: c# linq reflection lambda traversal


【解决方案1】:

我认为正如您所说,使用ExpressionVisitor 是一种很好的方法。您不需要实现所有Visit... 方法,因为它们已经具有默认实现。据我了解,您想要的是在 lambda 函数中找到某种类型的所有属性访问

public class MemberAccessVisitor : ExpressionVisitor
{
    private readonly Type declaringType;
    private IList<string> propertyNames = new List<string>();

    public MemberAccessVisitor(Type declaringType)
    {
        this.declaringType = declaringType;
    }

    public IEnumerable<string> PropertyNames { get { return propertyNames; } }

    public override Expression Visit(Expression expr)
    {
        if (expr != null && expr.NodeType == ExpressionType.MemberAccess)
        {
            var memberExpr = (MemberExpression)expr;
            if (memberExpr.Member.DeclaringType == declaringType)
            {
                propertyNames.Add(memberExpr.Member.Name);
            }
        }

        return base.Visit(expr);
    }
}

这可以通过检查成员是属性来进一步改进为您想要的,并且还可以获取PropertyInfo 而不是字符串

可以这样使用:

var visitor = new MemberAccessVisitor(typeof(TSource));

visitor.Visit(memberMap);

var propertyNames = visitor.PropertyNames;

【讨论】:

    猜你喜欢
    • 2015-09-11
    • 2021-03-14
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多