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 ExpressionVisitor的VisitMemberInit方法中,从中调用MemberInitExpression.Accept.所以在Accept这里似乎没有任何好处.
为什么不在基础中处理树ExpressionVisitor,忘记所有Accept方法呢?
我希望你理解我的观点,并希望有人能够了解这一实施背后的动机.可能我根本不了解访客模式?...
访问者可以覆盖任何表达式的访问方式。如果您的建议在所有地方都得到实施,那么访客就永远不会被召唤。所有访问逻辑都将被覆盖Accept。非 BCL 代码无法重写此方法。
如果你写visitor.Visit((Expression)this.SomeExpression)(就像你在问题中所做的那样)那么你将如何对 的类型执行动态调度SomeExpression?现在访问者必须执行动态调度。请注意,您的第二个代码片段做出了简化的假设:所有要访问的子表达式都具有已知类型。尝试编写代码来BinaryExpression看看我的意思。
也许我不明白什么,但这个建议没有意义。
该方法的目的Accept是性能优化。每个接受都是一个相当便宜的虚拟调用。另一种选择是在访问者中对表达式类型(这是一个枚举)进行巨大的切换。那可能会慢一些。