Expression Trees em C#: Consultas Dinâmicas e Otimizadas

Neste tutorial, exploraremos o uso de Expression Trees em C# para manipular consultas de forma dinâmica, oferecendo maior flexibilidade na criação e combinação de filtros, projeções e outros operadores. O objetivo é mostrar como construir e modificar consultas em tempo de execução, mantendo alta performance e clareza de códigoProgramação Funcional e LINQ: Abordagem para Maior LegibilidadeProgramação Funcional e LINQ: Abordagem para Maior LegibilidadeDescubra como aplicar conceitos funcionais com LINQ em C# para criar códigos mais legíveis, simples, robustos e fáceis de manter.. Veremos desde a ideia fundamental das árvores de expressão até exemplos práticos de aplicação.

Visão Geral🔗

1. Consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. Dinâmicas: Permitem construir filtros🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. e condições em tempo de execução.

2. Reuso de Lógica: Possibilitam combinar ou alterar expressões de forma mais simples.

3. Integração com LINQ🔍 LINQ Básico: Filtre Dados como um Garimpeiro Digital!🔍 LINQ Básico: Filtre Dados como um Garimpeiro Digital!Descubra como o LINQ facilita o processamento de dados em C#. Filtre, ordene e transforme coleções com precisão e eficiência no seu código.: Muitas implementações de LINQ (principalmente para bancos de dadosConceitos fundamentais de NoSQL: bases para trabalhar com MongoDB em C#Conceitos fundamentais de NoSQL: bases para trabalhar com MongoDB em C#Descubra os fundamentos do NoSQL e aprenda como utilizar MongoDB com C# para desenvolver aplicações .NET escaláveis e modernas até 2025.) transformam lambdas em Expression Trees para🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)🔄 Loops em C#: Repita Tarefas sem Enlouquecer (Com for e while!)Descubra como automatizar repetições em C# utilizando loops for e while com exemplos práticos que evitam erros e otimizam seu código. Aprenda mais! análise interna.

Conceitos Fundamentais🔗

Internamente, uma Expression Tree é formada por nós que representam parâmetros, constantes, propriedades⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!⚡ Propriedades: Get e Set com Elegância (e sem Campos Privados Bagunçados)!Aprenda como utilizar propriedades em C# para encapsular dados, validar informações e manter um código organizado, seguro e de fácil manutenção., métodos, operadores lógicos, entre outros. Cada nó é um objeto do tipo Expression ou de classes derivadas🧬 Herança: Reutilize Código sem Copiar e Colar (como um Jedi)!🧬 Herança: Reutilize Código sem Copiar e Colar (como um Jedi)!Aprenda a utilizar herança em C# para criar hierarquias de classes, reaproveitar código e manter projetos organizados de forma simples e escalável. (por exemplo, ParameterExpression, BinaryExpression, MethodCallExpression).

Principais classes🏗️ Classes vs. Structs: Quando Usar Cada Uma (e Não Quebrar a Cabeça)!🏗️ Classes vs. Structs: Quando Usar Cada Uma (e Não Quebrar a Cabeça)!Descubra como escolher entre classes e structs em C#. Aprenda sobre alocação de memória, passagem por valor e referência, e performance nesta explicação clara. de interesse:

ClasseDescrição
ParameterExpressionRepresenta um parâmetro dentro de uma expressão, como o x em x => x.Price > 100.
ConstantExpressionRepresenta um valor constante, como o 100 em x => x.Price > 100.
BinaryExpressionRepresenta operadores binários (>, <, ==, +, -, etc.).
MethodCallExpressionRepresenta a chamada a um método, seja de instância ou estático.
Expression<Func<T, R>>É a forma mais comum de expressar uma árvore de expressão que retorne um tipo específico R.

Estrutura de uma Expression Tree🔗

Para facilitar a visualização🎭 MVVM: Separe Regras de Negócio da Interface Graficamente!🎭 MVVM: Separe Regras de Negócio da Interface Graficamente!Descubra como o padrão MVVM separa a interface e a lógica de negócio, facilitando testes e manutenção, com exemplos e dicas práticas para seu projeto., abaixo temos um diagrama em mermaid que ilustra a estrutura básica de uma Expression Tree para uma consulta🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. simples:

graph LR A[LambdaExpression] --> B(ParameterExpression: p) A --> C(BinaryExpression: >) C --> D(PropertyExpression: p.Price) C --> E(ConstantExpression: 100)
Explicando o fluxo:
- O LambdaExpression é o nó raiz.
- Ele tem um ParameterExpression que representa o parâmetro p.
- No corpo (BodyExpression), há um BinaryExpression (>), que compara p.Price a 100.

Construindo uma Expression Tree🔗

Vejamos um exemplo prático📝 Logging com Serilog: Registre Tudo como um Detetive de Bugs!📝 Logging com Serilog: Registre Tudo como um Detetive de Bugs!Aprenda a usar Serilog em .NET para registrar logs estruturados, identificar erros e enriquecer informações, transformando seu código num enigma solucionável. de como construir manualmente uma expressão (p => p.Price > 100), passo a passo.

using System;
using System.Linq.Expressions;
public class Product
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}
public class ExpressionTreeExample
{
    public static void Main()
    {
        // Passo 1: Criar o parâmetro (p)
        ParameterExpression param = Expression.Parameter(typeof(Product), "p");
        // Passo 2: Criar a expressão que acessa a propriedade (p.Price)
        MemberExpression propertyAccess = Expression.Property(param, "Price");
        // Passo 3: Criar a constante 100
        ConstantExpression constant = Expression.Constant(100m, typeof(decimal));
        // Passo 4: Criar a expressão binária (p.Price > 100)
        BinaryExpression greaterThan = Expression.GreaterThan(propertyAccess, constant);
        // Passo 5: Converter em expressão lambda (p => p.Price > 100)
        Expression<Func<Product, bool>> lambda =
            Expression.Lambda<Func<Product, bool>>(greaterThan, param);
        // Passo 6: Compilar e usar
        Func<Product, bool> compiled = lambda.Compile();
        // Exemplo de uso
        var product = new Product { Name = "Tablet", Price = 150m };
        bool result = compiled(product);
        Console.WriteLine($"O product {product.Name} é maior que 100? {result}");
    }
}

Análise do Código

Manipulação de Consultas Dinâmicas🔗

A utilidade prática de Expression Trees surge, em particular, quando📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. precisamos dinamicamente criar ou combinar múltiplas condições de forma flexível. Por exemplo, criar diferentes condições de filtro🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. conforme as opções escolhidas pelo usuário.

Exemplo: Filtros Condicionais

Suponha que em um cenário real queiramos combinar filtros opcionais como, por exemplo, filtrar produtos🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. por Faixa de Preço e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. Nome Contendo certo termo. Podemos ir construindo as expressões passo a passo:

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
public static class DynamicFilter
{
    public static Expression<Func<Product, bool>> BuildFilter(
        decimal? minPrice,
        decimal? maxPrice,
        string nameContains)
    {
        // Parâmetro base
        ParameterExpression param = Expression.Parameter(typeof(Product), "p");
        // Expressão inicial: 'true'
        Expression filter = Expression.Constant(true);
        // Se minPrice estiver definido, adiciona 'p.Price >= minPrice'
        if (minPrice.HasValue)
        {
            var left = Expression.Property(param, "Price");
            var right = Expression.Constant(minPrice.Value, typeof(decimal));
            var condition = Expression.GreaterThanOrEqual(left, right);
            filter = Expression.AndAlso(filter, condition);
        }
        // Se maxPrice estiver definido, adiciona 'p.Price <= maxPrice'
        if (maxPrice.HasValue)
        {
            var left = Expression.Property(param, "Price");
            var right = Expression.Constant(maxPrice.Value, typeof(decimal));
            var condition = Expression.LessThanOrEqual(left, right);
            filter = Expression.AndAlso(filter, condition);
        }
        // Se nameContains não for nulo ou vazio, adiciona 'p.Name.Contains(...)'
        if (!string.IsNullOrWhiteSpace(nameContains))
        {
            var left = Expression.Property(param, "Name");
            var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
            var right = Expression.Constant(nameContains, typeof(string));
            var condition = Expression.Call(left, method, right);
            filter = Expression.AndAlso(filter, condition);
        }
        // Cria a expressão lambda e retorna
        return Expression.Lambda<Func<Product, bool>>(filter, param);
    }
}
// Uso de exemplo
public class ProductFilterTest
{
    public static void Main()
    {
        var products = new List<Product>
        {
            new Product { Name = "Notebook", Price = 3000m },
            new Product { Name = "Mouse", Price = 50m },
            new Product { Name = "Teclado", Price = 150m }
        };
        // Constrói a expressão de filtro
        var filterExpression = DynamicFilter.BuildFilter(minPrice: 100, maxPrice: null, nameContains: "o");
        // Compila e filtra a lista
        var filtered = products.AsQueryable().Where(filterExpression).ToList();
        foreach (var p in filtered)
            Console.WriteLine($"Produto: {p.Name}, Preço: {p.Price}");
    }
}

Destaques do Exemplo

Considerações de Performance🔗

Boas Práticas🔗

Dê nomes claros aos parâmetros🎯 Sobrecarga de Métodos: Um Nome, Múltiplos Superpoderes!🎯 Sobrecarga de Métodos: Um Nome, Múltiplos Superpoderes!Aprenda sobre a técnica de sobrecarga de métodos no C# com exemplos e práticas recomendadas para melhorar a organização e legibilidade do seu código. e métodos usados nas expressões para facilitar manutenção e depuração.

Teste cada possível combinação de parâmetros🎯 Sobrecarga de Métodos: Um Nome, Múltiplos Superpoderes!🎯 Sobrecarga de Métodos: Um Nome, Múltiplos Superpoderes!Aprenda sobre a técnica de sobrecarga de métodos no C# com exemplos e práticas recomendadas para melhorar a organização e legibilidade do seu código. para garantir que a expressão resultante gere o comportamento desejado.

  • Reaproveitamento de Blocos

Crie métodos🧠 Métodos em C#: Como Criar Funções que Não São Só Enfeites!🧠 Métodos em C#: Como Criar Funções que Não São Só Enfeites!Otimize seu código em C# com métodos inteligentes. Aprenda práticas de reutilização, sobrecarga e escopo para melhorar a clareza e a eficiência. auxiliares para expressões recorrentes, como checagem de null, comparação de intervalos etc.

Conclusão🔗

Com as Expression Trees, podemos criar e manipular consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. de forma programática e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. dinâmica, abrindo espaço para cenários📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. em que as condições de pesquisa são definidas apenas em tempo de execução. Seja para filtros elaborados, construção de queries complexas ou para cenários📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. avançados de refatoração de código, as árvores de expressão oferecem flexibilidade e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. potência.

A compilação dessas árvores em delegates de alto desempenho⏱️ Testes de Performance: Garanta Velocidade Além da Funcionalidade!⏱️ Testes de Performance: Garanta Velocidade Além da Funcionalidade!Descubra como medir, diagnosticar e otimizar performance em aplicações .NET com dicas práticas e ferramentas essenciais para devs. e a possibilidade de combiná-las de maneira elegante fazem com que seu uso seja não apenas interessante, mas também capaz de impulsionar a performance🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!🔄 StringBuilder: Quando Concatenar Strings Vira um Pesadelo!Descubra como o StringBuilder otimiza a concatenação em C#, evitando desperdício de memória e melhorando a performance das aplicações. Veja exemplos práticos! em cenários de consultas.

Estudar e📊 Behavior-Driven Development: Testes que Todo Mundo Entende!📊 Behavior-Driven Development: Testes que Todo Mundo Entende!Descubra como o BDD transforma testes em linguagens acessíveis. Aprenda a usar SpecFlow em C# para criar testes claros, colaborativos e sem ambiguidades. dominar o uso de Expression Trees é uma etapa essencial para quem deseja criar📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!📡 RESTful 101: Princípios que Todo Dev API Precisa Saber!Descubra os fundamentos do REST e boas práticas para criar APIs simples, escaláveis e eficientes. Domine métodos HTTP e status codes com exemplos práticos. soluções otimizadas e escaláveis em aplicações que exigem um alto grau de customização nas consultas🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!🎲 Desafio: Analise Dados de Vendas com LINQ e Coleções!Aprenda a usar coleções e LINQ em C# para analisar vendas, filtrar dados e extrair insights estratégicos que otimizem decisões e impulsionem seu negócio. de dados.

Autor: Marcelo V. Souza - Engenheiro de Sistemas e Entusiasta em IoT e Desenvolvimento de Software, com foco em inovação tecnológica.

Referências🔗

Compartilhar artigo

Artigos Relacionados