C#ExpressionVisitor实现的动机是什么?

Zol*_*ási 8 c# design-patterns visitor-pattern linq-expressions

我必须为任务设计一个解决方案,我想使用理论上类似于C#的ExpressionVisitor的东西.

为了好奇,我打开了.NET源代码ExpressionVisitor来查看它.从那时起,我一直在想为什么.NET团队实现了访问者.

例如,MemberInitExpression.Accept看起来像这样:

protected internal override Expression Accept(ExpressionVisitor visitor) {
    return visitor.VisitMemberInit(this);
}
Run Code Online (Sandbox Code Playgroud)

我 - 可能是菜鸟 - 问题是:它有意义吗?我的意思是,Accept方法本身不应该负责它如何实现访问本身?我的意思是我期待这样的事情(internal从外部去除可见性的可见性):

protected override Expression Accept(ExpressionVisitor visitor) {
    return this.Update(
            visitor.VisitAndConvert(this.NewExpression, "VisitMemberInit"),
            visitor.Visit(this.Bindings, VisitMemberBinding)
            );
}
Run Code Online (Sandbox Code Playgroud)

但是这个代码在base ExpressionVisitorVisitMemberInit方法中,从中调用MemberInitExpression.Accept.所以在Accept这里似乎没有任何好处.

为什么不在基础中处理树ExpressionVisitor,忘记所有Accept方法呢?

我希望你理解我的观点,并希望有人能够了解这一实施背后的动机.可能我根本不了解访客模式?...

usr*_*usr 3

访问者可以覆盖任何表达式的访问方式。如果您的建议在所有地方都得到实施,那么访客就永远不会被召唤。所有访问逻辑都将被覆盖Accept。非 BCL 代码无法重写此方法。

如果你写visitor.Visit((Expression)this.SomeExpression)(就像你在问题中所做的那样)那么你将如何对 的类型执行动态调度SomeExpression?现在访问者必须执行动态调度。请注意,您的第二个代码片段做出了简化的假设:所有要访问的子表达式都具有已知类型。尝试编写代码来BinaryExpression看看我的意思。

也许我不明白什么,但这个建议没有意义。

该方法的目的Accept是性能优化。每个接受都是一个相当便宜的虚拟调用。另一种选择是在访问者中对表达式类型(这是一个枚举)进行巨大的切换。那可能会慢一些。