Como: Use as árvores de expressão para criar consultas dinâmicas (C# e Visual Basic)

Em LINQ, árvores de expressão são usados para representar estruturadas de consultas que fontes de destino de dados que implementam IQueryable<T>. Por exemplo, o LINQ to SQL provedor implementa o IQueryable<T> interface para consultar armazenamentos de dados relacionais. C# e Visual Basic compiladores compilar as consultas de destino como fontes de dados no código que cria uma árvore de expressão em tempo de execução. O provedor de consultas pode percorrer a estrutura de dados de árvore de expressão e traduzi-la em uma linguagem de consulta apropriada para a fonte de dados.

Árvores de expressão também são usados em LINQ para representar as expressões lambda são atribuídas a variáveis do tipo Expression<TDelegate>.

Este tópico descreve como usar árvores de expressão para criar dinâmico LINQ consultas. Consultas dinâmicas são úteis quando as especificidades de uma consulta não são conhecidas no momento da compilação. Por exemplo, um aplicativo pode fornecer uma interface de usuário que permite ao usuário final especificar um ou mais predicados para filtrar os dados. Para usar LINQ para consultar, esse tipo de aplicativo deve usar árvores de expressão para criar o LINQ a consulta em tempo de execução.

Exemplo

O exemplo a seguir mostra como usar árvores de expressão para construir uma consulta em um IQueryable de fonte de dados e, em seguida, executam o proprietário. O código cria uma árvore de expressão para representar a consulta a seguir:

C# consulta

companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)

Consulta de Visual Basic

companies.Where(Function(company) company.ToLower() = "coho winery" OrElse company.Length > 16).OrderBy(Function(company) company)

Os métodos de fábrica na System.Linq.Expressions espaço para nome são usados para criar árvores de expressão, que representam as expressões que compõem a consulta geral. Consultem as expressões que representam as chamadas para métodos de operadores de consulta padrão a Queryable implementações dos seguintes métodos. Árvore de expressão final é passado para o CreateQuery<TElement>(Expression) a implementação do provedor da IQueryable a fonte de dados para criar uma consulta de executável do tipo IQueryable. Os resultados são obtidos, enumerando a variável de consulta.

        Dim companies = 
            {"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light", 
             "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works", 
             "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders", 
             "Blue Yonder Airlines", "Trey Research", "The Phone Company", 
             "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee"}

        ' The IQueryable data to query.
        Dim queryableData As IQueryable(Of String) = companies.AsQueryable()

        ' Compose the expression tree that represents the parameter to the predicate.
        Dim pe As ParameterExpression = Expression.Parameter(GetType(String), "company")

        ' ***** Where(Function(company) company.ToLower() = "coho winery" OrElse company.Length > 16) *****
        ' Create an expression tree that represents the expression: company.ToLower() = "coho winery".
        Dim left As Expression = Expression.Call(pe, GetType(String).GetMethod("ToLower", System.Type.EmptyTypes))
        Dim right As Expression = Expression.Constant("coho winery")
        Dim e1 As Expression = Expression.Equal(left, right)

        ' Create an expression tree that represents the expression: company.Length > 16.
        left = Expression.Property(pe, GetType(String).GetProperty("Length"))
        right = Expression.Constant(16, GetType(Integer))
        Dim e2 As Expression = Expression.GreaterThan(left, right)

        ' Combine the expressions to create an expression tree that represents the
        ' expression: company.ToLower() = "coho winery" OrElse company.Length > 16).
        Dim predicateBody As Expression = Expression.OrElse(e1, e2)

        ' Create an expression tree that represents the expression:
        ' queryableData.Where(Function(company) company.ToLower() = "coho winery" OrElse company.Length > 16)
        Dim whereCallExpression As MethodCallExpression = Expression.Call( 
                GetType(Queryable), 
                "Where", 
                New Type() {queryableData.ElementType}, 
                queryableData.Expression, 
                Expression.Lambda(Of Func(Of String, Boolean))(predicateBody, New ParameterExpression() {pe}))
        ' ***** End Where *****

        ' ***** OrderBy(Function(company) company) *****
        ' Create an expression tree that represents the expression:
        ' whereCallExpression.OrderBy(Function(company) company)
        Dim orderByCallExpression As MethodCallExpression = Expression.Call( 
                GetType(Queryable), 
                "OrderBy", 
                New Type() {queryableData.ElementType, queryableData.ElementType}, 
                whereCallExpression, 
                Expression.Lambda(Of Func(Of String, String))(pe, New ParameterExpression() {pe}))
        ' ***** End OrderBy *****

        ' Create an executable query from the expression tree.
        Dim results As IQueryable(Of String) = queryableData.Provider.CreateQuery(Of String)(orderByCallExpression)

        ' Enumerate the results.
        For Each company As String In results
            Console.WriteLine(company)
        Next

        ' This code produces the following output:
        '
        ' Blue Yonder Airlines
        ' City Power & Light
        ' Coho Winery
        ' Consolidated Messenger
        ' Graphic Design Institute
        ' Humongous Insurance
        ' Lucerne Publishing
        ' Northwind Traders
        ' The Phone Company
        ' Wide World Importers

            string[] companies = { "Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
                               "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
                               "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
                               "Blue Yonder Airlines", "Trey Research", "The Phone Company",
                               "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };

            // The IQueryable data to query.
            IQueryable<String> queryableData = companies.AsQueryable<string>();

            // Compose the expression tree that represents the parameter to the predicate.
            ParameterExpression pe = Expression.Parameter(typeof(string), "company");

            // ***** Where(company => (company.ToLower() == "coho winery" || company.Length > 16)) *****
            // Create an expression tree that represents the expression 'company.ToLower() == "coho winery"'.
            Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
            Expression right = Expression.Constant("coho winery");
            Expression e1 = Expression.Equal(left, right);

            // Create an expression tree that represents the expression 'company.Length > 16'.
            left = Expression.Property(pe, typeof(string).GetProperty("Length"));
            right = Expression.Constant(16, typeof(int));
            Expression e2 = Expression.GreaterThan(left, right);

            // Combine the expression trees to create an expression tree that represents the
            // expression '(company.ToLower() == "coho winery" || company.Length > 16)'.
            Expression predicateBody = Expression.OrElse(e1, e2);

            // Create an expression tree that represents the expression
            // 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'
            MethodCallExpression whereCallExpression = Expression.Call(
                typeof(Queryable),
                "Where",
                new Type[] { queryableData.ElementType },
                queryableData.Expression,
                Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));
            // ***** End Where *****

            // ***** OrderBy(company => company) *****
            // Create an expression tree that represents the expression
            // 'whereCallExpression.OrderBy(company => company)'
            MethodCallExpression orderByCallExpression = Expression.Call(
                typeof(Queryable),
                "OrderBy",
                new Type[] { queryableData.ElementType, queryableData.ElementType },
                whereCallExpression,
                Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));
            // ***** End OrderBy *****

            // Create an executable query from the expression tree.
            IQueryable<string> results = queryableData.Provider.CreateQuery<string>(orderByCallExpression);

            // Enumerate the results.
            foreach (string company in results)
                Console.WriteLine(company);

            /*  This code produces the following output:

                Blue Yonder Airlines
                City Power & Light
                Coho Winery
                Consolidated Messenger
                Graphic Design Institute
                Humongous Insurance
                Lucerne Publishing
                Northwind Traders
                The Phone Company
                Wide World Importers
            */

Esse código usa um número fixo de expressões no predicado que é passado para o Queryable.Where método. No entanto, você pode escrever um aplicativo que combina um número variável de expressões de predicado que depende da entrada do usuário. Você também pode variar os operadores de consulta padrão que são chamados na consulta, dependendo da entrada do usuário.

Compilando o código

  • Criar uma nova Aplicativo de Console projeto em Visual Studio.

  • Adicione uma referência a System.Core.dll se já não é referenciado.

  • Inclua o namespace System.Linq.Expressions.

  • Copie o código do exemplo e colá-lo para o Main método (C#) ou o Main Sub procedimento (Visual Basic).

Consulte também

Tarefas

Como: Executar as árvores de expressão (C# e Visual Basic)

Como: especificar dinamicamente o predicado filtros em tempo de execução (guia de programação TRANSLATION FROM VPE FOR CSHARP)

Conceitos

Árvores de expressão (C# e Visual Basic)

Outros recursos

Semente de Farm LINQ: Usando o Visualizador de árvore de expressão