Какова мотивация реализации C# ExpressionVisitor?

Я должен разработать решение для задачи, и я хотел бы использовать что-то теоретически похожее на ExpressionVisitor C#.

для любопытства я открыл источники .NET для ExpressionVisitor чтобы взглянуть на него. С тех пор мне было интересно, почему команда .NET реализовала посетителя так, как они это сделали.

MemberInitExpression.Accept выглядит так:
protected internal override Expression Accept(ExpressionVisitor visitor) {
    return visitor.VisitMemberInit(this);
}

мой-вероятно, нуб-вопрос: имеет ли это смысл? Я имею в виду не метод принимает себя ответственность, как он реализует через себя? Я имею в виду, что я ожидал чего-то подобного (удаление internal видимость должна быть переопределена извне):

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

но этот код находится в базе ExpressionVisitor ' s VisitMemberInit метод, который вызывается из MemberInitExpression.Accept. Так что, похоже, не какая-либо польза от Accept реализация здесь.

почему бы просто не обработать дерево базы ExpressionVisitor, и забудьте обо всех Accept методы?

надеюсь, вы понимаете мои замечания и надеетесь, что кто-то может пролить свет на мотивацию этой реализации. Возможно, я вообще не понимаю, что такое визитеры?...

2 ответов


посетитель может переопределить способ выражения не посещают. Если бы ваше предложение было реализовано во всех местах, посетитель никогда бы не был вызван. Вся логика посещения была бы в переопределениях Accept. Код, отличный от BCL, не может переопределить этот метод.

если вы пишите visitor.Visit((Expression)this.SomeExpression) (Как вы делаете в вопросе), то как вы собираетесь выполнять динамическую отправку по типу SomeExpression? Теперь посетитель должен выполнить динамическую отправку. Обратите внимание, что ваш 2nd фрагмент кода делает упрощающее предположение, что все под-выражения, которые нужно посетить, имеют известный тип. Попробуйте написать код BinaryExpression чтобы увидеть, что я имею в виду.

может быть, я чего-то не понял, но это предложение не имеет смысла.

цель Accept метод-это оптимизация производительности. Каждый accept-это виртуальный вызов, который довольно дешев. Альтернативой было бы иметь огромный переключатель в посетителе над типом выражения (который является перечислением). Наверное замедлившийся.


шаблон посетителя позволяет алгоритму по существу быть отделенным от структуры, на которой он работает. В этом случае структура, с которой он работает, является деревом выражений.

заметил, что Accept метод в посетителе virtual. Это означает, что мы могли бы написать различные реализации ExpressionVisitor которые делают разные вещи с деревом выражений (и, действительно, существуют разные реализации). И мы можем сделать это без изменения кода в сами классы дерева выражений.

примеры различных реализаций посетителей могут быть чем-то вроде одного посетителя, который превращает дерево выражений обратно в строку, представляющую код C# (или, возможно, код на другом языке).