LINQ表达式树

时间:2014-10-17 11:17:19

标签: c# linq expression

我在一本关于LINQ的书中读到,有可能手动为查询构建表达式树(使用Expression类的成员)。它写在那里可能需要一些准确的查询调优,通常的查询操作员无法执行。我无法想象这种情况,有人能给我一些例子吗? 感谢。

2 个答案:

答案 0 :(得分:1)

//这是动态构建此查询的示例:

companies.Where(company =>(company.ToLower()==“coho winery”|| company.Length> 16))。OrderBy(company => company)

        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
        */

答案 1 :(得分:0)

通常,当在编译时不知道实体或集合类型时,或者当查询不能被硬编码时(例如,允许用户提供的组/排序/过滤标准),可以执行此操作。这可能很麻烦,因此像Dynamic LINQ这样的库的出现允许您侧面执行此过程并动态地将查询条件构造为文本。然后,这些库将解析您的条件并自行执行表达式树构造,类似于使用Expression API手动构建它的方式。

除此之外,我只能想到一个额外的情况,当必要手动构建树时:当你引用Expression<TDelegate>时,你想要包含它作为另一个表达式树中的嵌套表达式。即使所有内容都是静态类型的,您也无法在C#中使用lambda表达式直接执行此操作,因为您无法Invoke嵌套表达式(您可以调用TDelegate,但不能Expression<TDelegate>)。因此,您必须手动构建树。有关示例,请参阅this answer to another question