Какова мотивация реализации 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# (или, возможно, код на другом языке).