统计一个表达式树拥有的节点数量
2009-10-31 21:05 Jeffrey Zhao 阅读(17138) 评论(9) 编辑 收藏 举报如果要统计表达式树的节点数量,我们可以编写一个Expression Visitor来完成这个任务:
public class ExpressionNodeCounter : ExpressionVisitor { public int Calculate(Expression expr) { this.m_count = 0; this.Visit(expr); return this.m_count; } private int m_count; protected override Expression Visit(Expression exp) { this.m_count++; return base.Visit(exp); } }
我们将表达式树传递给Visit方法后,Visit方法会将参数分派给其它方法,而其它方法又会将子节点交还给Visit方法进行递归调用,因此我们可以得知其实这个表达式树的每个节点都会“经过”Visit方法处理。因此,我们只需要重载Visit方法,查看它调用了几次就行了。值得注意的是,由于ExpressionVisitor只负责“遍历”,因此在进行“统计”、“收集信息”等任务的时候,都需要在子类内部保存临时信息。因此,许多ExpressionVisitor的实现其实都不是线程安全的。这点在使用或设计的时候都值得注意,我在开发FastLambda项目时,也对这个问题疏忽了。因此,虽然我用了一些方式来保证了FastEvaluator的线程安全,但事实上在相当长的时间内其实它都有着严重的问题。
那么,我们现在便可以用ExpressionNodeCounter来统计上次使用不同方式生成URL时所用到的Lambda表达式:
var blog = new Blog(); var post = new Post(); Expression<Action<HomeController>> expr = c => c.Post(blog, post); Console.WriteLine(new ExpressionNodeCounter().Calculate(expr));
猜猜看结果如何?答案是7个节点,您是否能将它们一一指出?
其实,一般说来,由于自动生成闭包等机制,一个Lambda表达式实际构造出的节点总比我们“看出”的要多一些。