Pull to refresh

Expression Trees и оптимизация Reflection

Reading time 3 min
Views 6.3K
.NET *
В последней версии .NET Framework среди новых возможностей было добавлено средства метапрограммирования под названием Expression Trees. На базе этой технологии, а именно основываясь на том принципе, что выражения на "обычном" языке программирования могут автоматически преобразовываться в синтаксические деревья, была разработана технология LINQ.

Но в этом посте речь пойдет о другой области применения возможности динамически собирать expression trees и компилировать их в работоспособный код. И эта область — оптимизация Reflection.

кросс-пост с персонального блога
читать далее
Total votes 38: ↑29 and ↓9 +20
Comments 29

Разработка механизма извлечения DTO из БД с помощью LINQ

Reading time 9 min
Views 6.4K
.NET *
Sandbox
Постановка задачи

В этой статье я опишу механизм создания DTO, реализованный в одном из проектов нашей компании. Проект состоит из серверной части и нескольких клиентов (Silverlight, Outlook, iPad). Сервер представляет собой ряд сервисов, реализованных на WCF. Раз есть сервисы, то надо обмениваться с ними какими-то данными. Вариант, когда клиенты знают о сущностях доменной области и получают их с сервера, отпал сразу по ряду причин:

  1. Не все клиенты реализованы на .NET
  2. Возможные проблемы сериализации сложных графов объектов
  3. Избыточность передаваемых данных

В принципе, все эти недостатки давно известны и для их устранения умные люди придумали паттерн Data Transfer Object (DTO). То есть, классы сущностей доменной области известны только серверу, клиенты же оперируют классами DTO и экземплярами этих же классов обмениваются с сервисами. В теории все прекрасно, на практике же среди прочих возникают вопросы создания DTO и записи в них данных из сущностей. В небольших проектах с этой работой отлично справится оператор "=". Но, когда размер проекта начинает расти и повышаются требования к производительности и сопровождаемости кода, возникает необходимость в более гибком решении. Ниже я опишу эволюцию механизма, который мы используем для создания и заполнения DTO.
Читать дальше →
Total votes 7: ↑4 and ↓3 +1
Comments 12

Устранение дублирования Where Expressions в приложении

Reading time 4 min
Views 19K
.NET *C# *
Допустим, у вас есть товары и категории. В какой-то момент клиент сообщает, что для категорий с рейтингом > 50 необходимо использовать другие бизнес-процессы. У вас достаточно опыта и вы понимаете, что где сегодня 50 завтра будет 127.37 и хотите избежать появления магических чисел в коде, поэтому делаете так:

    public class Category : HasIdBase<int>
    {
        public static readonly Expression<Func<Category, bool>> NiceRating = x => x.Rating > 50;

       //...
    }

    var niceCategories = db.Query<Category>.Where(Category.NiceRating);

К сожалению, этот номер не пройдет, если вы хотите выбрать продукты из соответствующих категорий, потому что NiceRating имеет тип Expression<Func<Category, bool>>, а в случае с Product нам потребуется Expression<Func<Product, bool>>. То есть, необходимо осуществить преобразование Expression<Func<Category, bool>> => Expression<Func<Product, bool>>.

    public class Product: HasIdBase<int>
    {
        public virtual Category Category { get; set; }

       //...
    }

    var niceProductsCompilationError = db.Query<Product>.Where(Category.NiceRating); // так нельзя!

К счастью, осуществить это довольно просто!
Код под катом
Total votes 22: ↑18 and ↓4 +14
Comments 82

Готовим ORM, не отходя от плиты. Генерируем SQL — запрос на основе бинарных деревьев выражений

Reading time 9 min
Views 11K
.NET *ASP *C# *
image

Статья является продолжением первой части. В посте рассмотрим построение SQL-запроса по объектной модели типа, в виде бинарного дерева выражений и сопутствующие темы параметризации SQL-запросов, оптимизации рефлексии. Темы этой статьи сами по себе весьма обособленны, поэтому можно читать особо не обращая внимание на первую часть. Еще раз отмечу, данное решение, является «дело было вечером — делать было нечего» и не претендует на лавры промышленного продукта.
Читать дальше →
Total votes 18: ↑15 and ↓3 +12
Comments 12

EntityFramework: (анти)паттерн Repository

Reading time 15 min
Views 100K
Perfect code *.NET *Designing and refactoring *C# *
Sandbox
Repository Pattern
Репозиторий является посредником между слоем доступа к данным и доменным слоем,
работая как in-memory коллекция доменных обектов. Клиенты создают декларативные
описания запросов и передают их в репозиторий для выполнения.
  — свободный перевод Мартина Фаулера

EntityFraemwork предоставляет нам готовую реализацию паттернов Repository: DbSet<T> и UnitOfWork: DbContext. Но мне часто приходится видеть, как коллеги используют в своих проектах собственную реализацию репозиториев поверх существующих в EntityFraemwork.


Чаще всего используется один из двух подходов:


  1. Generic Repository как попытка абстрагироваться от конкретного ORM.
  2. Repository как набор запросов к выбранной таблице БД (паттерн DAO).

И каждый из этих подходов содержит недостатки.

Читать дальше →
Total votes 47: ↑45 and ↓2 +43
Comments 159

Internal DSL & Expression Trees — динамическое создание функций serialize, copy, clone, equals (Часть I)

Reading time 19 min
Views 8K
.NET *C# *


Статья посвящена двойному применению API Expression Trees — для разбора выражений и для генерации кода. Разбор выражений помогает построить структуры представления (они же структуры представления проблемно-ориентированного языка Internal DSL), а кодогенерация позволяет динамически создавать эффективные функции — наборы инструкций задаваемые структурами представления.


Демонстрировать буду динамическое создание итераторов свойств: serialize, copy, clone, equals. На примере serialize покажу как можно оптимизировать сериализацию (по сравнению с потоковыми сериализаторами) в классической ситуации, когда "предварительное" знание используется для улучшения производительности. Идея в том, что вызов потокового сериалайзера всегда проиграет "непотоковой" функции точно знающей какие узлы дерева надо обойти. При этом такой сериализатор создается "не руками" а динамически, но по заранее заданным правилам обхода. Предложенный Inernal DSL решает задачу компактного описания правил обхода древовидных структур объектов по их свойствам/properties (а в общем случае: обхода дерева вычислений c проименованием узлов) . Бенчмарк сериализатора скромный, но он важен тем, что добавляет подходу, построенному вокруг применения конкретного Internal DSL Includes (диалект того Include/ThenInclude что из EF Core) и применению Internal DSL в целом, необходимой убедительности.

Читать дальше →
Total votes 33: ↑33 and ↓0 +33
Comments 20

Деревья выражений в enterprise-разработке

Reading time 19 min
Views 37K
JUG Ru Group corporate blog Programming *.NET *System Programming *Compilers *
Для большинства разработчиков использование expression tree ограничивается лямбда-выражениями в LINQ. Зачастую мы вообще не придаем значения тому, как технология работает «под капотом».

В этой статье я продемонстрирую вам продвинутые техники работы с деревьями выражений: устранение дублирования кода в LINQ, кодогенерация, метапрограммирование, транспиляция, автоматизация тестирования.

Вы узнаете, как пользоваться expression tree напрямую, какие подводные камни приготовила технология и как их обойти.



Под катом — видео и текстовая расшифровка моего доклада с DotNext 2018 Piter.
Читать дальше →
Total votes 45: ↑45 and ↓0 +45
Comments 11

Помогаем Queryable Provider разобраться с интерполированными строками

Reading time 5 min
Views 6.8K
Programming *.NET *C# *
Sandbox

Тонкости Queryable Provider


Queryable Provider не справляется вот с этим:


 var result = _context.Humans
                      .Select(x => $"Name: {x.Name}  Age: {x.Age}")
                      .Where(x => x != "")
                      .ToList();

Он не справится с любым выражением, которое будет использовать интерполированную строку, но без трудностей разберет такое:


 var result = _context.Humans
                      .Select(x => "Name " +  x.Name + " Age " + x.Age)
                      .Where(x => x != "")
                      .ToList();

Особенно болезненно править баги после включение ClientEvaluation(исключениe при вычислении на клиенте), все профайлы автомаппера должны быть подвергнуты жесткому анализу, на поиск этой самой интерполяции. Давайте разберемся в чем дело и предложим свое решение проблемы

Читать дальше →
Total votes 37: ↑37 and ↓0 +37
Comments 18

Let's help QueryProvider deal with interpolated strings

Reading time 5 min
Views 1.4K
Website development *Programming *.NET *Designing and refactoring *C# *
Translation

Specifics of QueryProvider


QueryProvider can’t deal with this:


var result = _context.Humans
                      .Select(x => $"Name: {x.Name}  Age: {x.Age}")
                      .Where(x => x != "")
                      .ToList();

It can’t deal with any sentence using an interpolated string, but it’ll easily deal with this:


var result = _context.Humans
                      .Select(x => "Name " +  x.Name + " Age " + x.Age)
                      .Where(x => x != "")
                      .ToList();

The most painful thing is to fix bugs after turning on ClientEvaluation (exception for client-side calculation), since all Automapper profiles should be strictly analyzed for interpolation. Let’s find out what’s what and propose our solution to the problem.

Read more →
Total votes 12: ↑11 and ↓1 +10
Comments 0

Свой mapper или немного про ExpressionTrees

Reading time 7 min
Views 14K
.NET *C# *
Sandbox
image

Сегодня мы поговорим про то, как написать свой AutoMapper. Да, мне бы очень хотелось рассказать вам об этом, но я не смогу. Дело в том, что подобные решения очень большие, имеют историю проб и ошибок, а также прошли долгий путь применения. Я лишь могу дать понимание того, как это работает, дать отправную точку для тех, кто хотел бы разобраться с самим механизмом работы «мапперов». Можно даже сказать, что мы напишем свой велосипед.
Читать дальше →
Total votes 20: ↑20 and ↓0 +20
Comments 16

Свой конвертер JSON или ещё немного про ExpressionTrees

Reading time 8 min
Views 9.1K
.NET *C# *


Сериализация и десериализация — типичные операции, к которым современный разработчик относится как к тривиальным. Мы общаемся с базами данных, формируем HTTP-запросы, получаем данные через REST API, и часто даже не задумываемся как это работает. Сегодня я предлагаю написать свой сериализатор и десериализатор для JSON, чтобы узнать, что там «под капотом».
Читать дальше →
Total votes 19: ↑19 and ↓0 +19
Comments 20

Деревья выражений в C# на примере нахождения производной (Expression Tree Visitor vs Pattern matching)

Reading time 18 min
Views 28K
.NET *C# *ООP *
Доброго времени суток. Деревья выражений, особенно в сочетании с паттерном Visitor, всегда являлись довольно запутанной темой. Поэтому чем больше разнообразной информации по этой теме, чем больше примеров, тем легче интересующимся будет найти что-то, что им понятно и полезно.


Читать дальше →
Total votes 14: ↑13 and ↓1 +12
Comments 3

Оживляем деревья выражений кодогенерацией

Reading time 8 min
Views 12K
.NET *Visual Studio *C# *Xamarin *
Sandbox

Expression Trees — это, пожалуй, самое удобное средство манипуляции кодом в run-time.

Расширять код метапрограммами в compile-time позволяют Roslyn Source Generators, с ними это стало проще, чем когда-либо.

Пора использовать одно во благо другого, даже если мир к этому еще не совсем готов.

Читать далее
Total votes 32: ↑32 and ↓0 +32
Comments 17

Делаем фильтры «как в экселе» на ASP.NET Core

Reading time 6 min
Views 6.5K
Website development *.NET *C# *

«Сделайте нам фильтры «как в экселе», — довольно популярный запрос на разработку. К сожалению, реализация запроса в общем виде «слегка» длинее, чем его лаконичная постановка. Если вдруг вы никогда не пользовались этими фильтрами, то вот пример. Основная фишка в том, что в строчке с названиям колонок появляются выпадающие списки со значениями из выбранного диапазона. Например в колонках А и B — 4000 строк и 3999 значений (первую строчку занимают названия колонок). Таким образом, в соответсвтующих выпадающих списках будет по 3999 значений. В колонке C — 220 строк и 219 значений в выпадающем списке соответственно.


Пример реализации на C# под катом
Total votes 16: ↑15 and ↓1 +14
Comments 9

Транслируй меня полностью

Reading time 8 min
Views 7.2K
.NET *Designing and refactoring *C# *


Вы когда-нибудь работали с Entity Framework или другим ORM и получали NotSupportedException? Многие люди получали:


InvalidOperationException: Error generated for warning 'Microsoft.EntityFrameworkCore.Query.QueryClientEvaluationWarning: The LINQ expression could not be translated and will be evaluated locally.'

Марк Симан твердо убежден, что, за одним исключением, все существующие реализации нарушают LSP. Он даже готов отправить бесплатную копию своей книги первому читателю, который укажет ему на реальную, общедоступную реализацию IQueryable<T>, которая может принять любое выражение и не выбросить исключение. За девять лет книга так и не нашла своего обладателя:)


  • Hi Mark,
    I am writing a blog post that refers to your artticle. I am wondering if you have ever sent a free copy of your book to someone. Presumably not:)
  • Hi Maxim
    That’s right: I haven’t.
    Regards
    Mark Seemann

В поддержку этой точки зрения можно привести и другие аргументы. Например, ToListAsync вообще отсутствует в наборе методов расширения из коробки. Вместо этого он определен в пакетах конкретных ORM. Значит ли это, что не стоит раскрывать IQueryable<T> в публичных API? Я думаю, что ответ на этот вопрос — «зависит».

Читать дальше →
Total votes 5: ↑5 and ↓0 +5
Comments 27

Cоздание переиспользуемых Linq фильтров (построителей предикатов для Where), которые можно применять для разных типов

Reading time 4 min
Views 3.7K
Programming *.NET *C# *
Tutorial

Способ создания переиспользуемых Linq фильтров (построителе предикатов для условия Where), которые можно применять для разных типов объектов. Поля объектов для фильтрации указываются с помощью MemberExpression.

Способ подходит для Entity Framework, включая Async операции.

Читать далее
Total votes 1: ↑1 and ↓0 +1
Comments 5

Компилятор бизнес-правил на основе деревьев выражений

Reading time 11 min
Views 2.9K
Arcadia corporate blog Programming *.NET *C# *Microsoft Azure *

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

К коду
Total votes 5: ↑5 and ↓0 +5
Comments 9

Возможно вам не нужен AutoMapper

Reading time 7 min
Views 7.7K
Programming *.NET *C# *ООP *
✏️ Technotext 2022

Вы знали, что AutoMapper и MediatR создал один и тот же человек?

Джимми Богард создал две крайне обсуждаемые и спорные темы в .NET разработке. Если с MediatR уже разобрались, то c AutoMapper также хотелось бы расставить все точки над "ё".

В этой статье хочу поговорить об истории возникновения библиотеки. О том какую задачу она была призвана решать изначально. И уделить внимание её недостаткам.

Читать далее
Total votes 14: ↑12 and ↓2 +10
Comments 34