Как стать автором
Обновить

Комментарии 12

А про паттерн Visitor, и про то, что в .net есть готовый ExpressionVisitor, вы никогда не слышали?

Я тоже был уверен, что это первое о чём ты узнаешь разбираясь с деревьями выражений.
Знаю, но цель моего досуга в реализациях с нуля. Но я должен был упомянуть об этом в статье, поправлю.

Ну так в реализации с нуля тоже надо использовать паттерн Visitor.

Вы, правы. Вот и задачка появилась, переписать на этот паттерн )

А вот так не проще было?


    private Func<object, object> GetGetterMethod()
    {
        if (_property == null)
            throw new ArgumentNullException("property");

        var p = Expression.Parameter(typeof(object));
        var body = Expression.Property(Expression.Convert(p, _property.DeclaringType), _property);
        return Expression.Lambda<Func<object, object>>(Expression.Convert(body, typeof(object)), p).Compile();
    }

А еще лучше — собирать функцию для преобразования объекта целиком, а не по одному свойству. Это сэкономит кучу времени на вызовах делегатов.

Это гипотетическое упражнение, или готовые варианты типа Entity Framework, LINQ to SQL или ServiceStack.OrmLite вас по каким-то конкретным причинам не устроили?
Это гипотетическое упражнение, конечно. Меня они так или иначе устраивают.

Теперь по пунктам:


Разбор выражений удобно осуществлять на основе бинарных деревьев выражений.

Разбор выражений удобно осуществлять на основе деревьев выражений. Expressions в .net — не бинарное дерево, а просто дерево: у ConditionalExpression три дочерних выражения, у MethodCallExpression и MemberInitExpression — неограниченный список.


Нам важно добраться до листьев, которые в нашем случае, имеют типы MemberExpression, ConstantExpression

То есть условия вида x != 2 вы не поддерживаете?


Код функционала реализации построения SQL

Что случится, если я напишу Where(x => 2 < x.Age)?


var name = expField.Member.Name;
var prop = CacheTypeReflectionWrapper.GetProps(type).Where(x => x.FieldNameAttributes.Any()).First(x => x.Name.Equals(name));

Эмм. Во-первых, в MemberExpression может быть не только свойство. Во-вторых, там уже есть MemberInfo, зачем его где-то искать. В-третьих, если уж вы его где-то ищете, ну возьмите вы словарь (с правильным компарером).


var attrs = prop.FieldNameAttributes;
fieldName = attrs.First()

Я даже не буду спрашивать, почему их может быть больше одного.


var unaryNode = left.Right as UnaryExpression;
if (unaryNode != null)
{
expValue = unaryNode.Operand as ConstantExpression;
if (expValue != null)
{
InitParams(command, strBuilder, fieldName, parameter, expValue);
}
}

Вы никогда не слышали, что бывает унарная операция Not?

То есть условия вида x != 2 вы не поддерживаете?

Отвечу за автора. Параметр выражения — это всегда объект, представляющий строку таблицы (проекции автором не реализованы). А сравнение строки таблицы с чем бы то ни было целиком бессмысленно.

А сравнение строки таблицы с чем бы то ни было целиком бессмысленно.

Если считать, что проекций нет и не будет, и джойнов тоже никогда не будет...


Пойнт, впрочем, был не в этом, а в том, что есть много разных полезных вещей, которые имеют семантически адекватную конверсию в SQL (начиная с string.StartsWith), но которые автор не замечает. Хуже того, автор считает, что любой MemberExpression взят от параметра выражения — что, очевидно, легко опровергается чем-нибудь навроде x.Year == DateTime.Now.Year.

Что случится, если я напишу Where(x => 2 < x.Age)?

Тут автор не одинок. В языке запросов MS Dynamics CRM (Entity2Crm) все упадет :-)

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории