遍历表达式树并提取参数

时间:2015-07-20 11:56:59

标签: c# linq reflection lambda traversal

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

   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(可以是字符串[],PropertyInfo很容易转换为。)

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

1 个答案:

答案 0 :(得分:4)

我认为,正如您所说,使用ExpressionVisitor是一种很好的方法。您不需要实现所有ZooKeeper zk = new ZooKeeper(KafkaContextLookupUtil.getZookeeperConnect().getZkConnect(), 10000, null); List<String> ids = zk.getChildren("/brokers/ids", false); List<Map> brokerList = new ArrayList<>(); ObjectMapper objectMapper = new ObjectMapper(); for (String id : ids) { Map map = objectMapper.readValue(zk.getData("/brokers/ids/" + id, false, null), Map.class); brokerList.add(map); } return brokerList; 方法,因为它们已经具有默认实现。根据我的理解你想要的是在lambda函数中找到某种类型的所有属性访问

Visit...

通过检查成员是属性还是获取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