简体   繁体   English

遍历表达式树并提取参数

[英]Traverse an expression tree and extract parameters

I'm writing a kind of a mapping tool. 我正在写一种绘图工具。 I have a method that looks like this (simplified): 我有一个看起来像这样的方法(简化):

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

The memberMap is an expression defining how to transform a property from TSource to TTarget . memberMap是一个表达式,用于定义如何将属性从TSource转换为TTarget For the business logic, I need to extract all references to properties of TSource from it. 对于业务逻辑,我需要从中提取对TSource属性的所有引用。 For example, from 例如,来自

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

I would like to get Customers , and from 我想得到Customers ,来自

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

FirstName and LastName (could be as string[], PropertyInfo is trivial to convert to). FirstNameLastName (可以是string [], PropertyInfo很容易转换为)。

How would I do this? 我该怎么做? My first approach was to traverse the tree manually, checking the node type and inspecting different properties depending on the node type (eg Operand for unary expressions, Arguments for a function call) to determine of any of these are a property of TSource . 我的第一种方法是手动遍历树,检查节点类型并根据节点类型检查不同的属性(例如,一元表达式的Operand ,函数调用的Arguments )以确定其中任何一个是TSource的属性。 Then I discovered the expression kind list and I gave up -- even if I support only the most common kinds, it's still lots of work. 然后我发现了表达式列表 ,我放弃了 - 即使我只支持最常见的类型,它仍然有很多工作。 Then I found the ExpressionVisitor . 然后我找到了ExpressionVisitor It looks better, but it's still a lot of work to override the visitor methods and I'd like to know if there's an other option, using perhaps a more specialised framework, before I devote my time to this. 它看起来更好,但是覆盖访问者方法仍然需要做很多工作,而且我想知道是否还有其他选择,可能使用更专业的框架,然后再投入时间。

I think as you've said that using ExpressionVisitor works out to be a good approach. 我想你已经说过使用ExpressionVisitor是一个很好的方法。 You don't need to implement all the Visit... methods as they already have a default implementation. 您不需要实现所有Visit...方法,因为它们已经具有默认实现。 From what I understood what you want is to find all property accesses of a certain type inside a lambda function 根据我的理解你想要的是在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);
    }
}

This could be further improved to what you want by checking the member is a property and also to get PropertyInfo rather than strings 通过检查成员是属性以及获取PropertyInfo而不是字符串,可以进一步将其改进为您想要的

It could be used as follows: 它可以使用如下:

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

visitor.Visit(memberMap);

var propertyNames = visitor.PropertyNames;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM