Комментарии 2
Спасибо автору за статью! Действительно полезная информация касательно деревьев выражений, собранная в одном месте.
Я на визиторы смотрю как на ужас. Наверное наша ORM давно бы погрязла в куче кассов и непонятных иерархий.
Простая, постоянно требующя решения задача подмены параметра в теле лямбды превращается в армагеддон. Да она решается созданием одного ReplacingExpressionVisitor (такой себе класик)
И такого вызова:

var newParam = Expression.Parameter(someType); 
var newBody = ReplacingExpressionVisitor.Replace(lambda.Paramters[0], newParam, lambda.Body);

А еще она решаться может и вот так:
var newParam = Expression.Parameter(someType); 
var newBody = lambda.Body.Transform(e => e == lambda.Paramters[0] ? newParam : e);


Вроде одинаково, но гипотетически усложним задачу, мало того, что надо подменить параметр, так и прибавить единички ко всем целочисленным константам. Тут уже надо городить новые классы или даже пропускать через несколько визиторов, а мы в лямбде для Transform просто усложняем условие. Это может быть ощутимо заметно на гигантском дереве, такие иногда получаются когда запрос к базе содержит монструидальный Where, созданный динамичиски какой-то UI библиотекой.

Минус Transform в том что если вы придумываете кастомные Expression, тут уже сильно не потрансформируешь, или придется расширять метод.

Если интересна реализация, ее можно найти в библиотеке CodeJam или в нашей ORM linq2db.

В защиту данного подхода скажу так, за 5 лет мне ни разу не пришлось писать новый Visitor.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.