田敏
返回博客列表
技术

Expression的用法

田敏
2024-12-052 分钟阅读
.NETC#Backend

ExpressionIQueryable 是 .NET 中非常重要的特性,特别是在处理动态 LINQ 查询、延迟执行等场景时。以下是它们的详细解析与用法。


1. Expression 的用法

1.1 概述

  • Expression 是一个表达式树,可以用来描述代码(比如 lambda 表达式)结构,而不实际执行代码。
  • 它常用在动态 LINQ 查询、构建动态条件等场景中。

核心类

  • Expression<TDelegate>:表示具有强类型的表达式树。
  • 常用 Func<T, TResult>Action<T> 作为泛型参数。

1.2 用法示例

1.2.1 动态构建表达式树

用来动态生成查询条件。

using System;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        // 定义一个参数 x
        ParameterExpression param = Expression.Parameter(typeof(int), "x");

        // 定义表达式 x > 5
        Expression body = Expression.GreaterThan(param, Expression.Constant(5));

        // 构建 Lambda 表达式 x => x > 5
        Expression<Func<int, bool>> lambda = Expression.Lambda<Func<int, bool>>(body, param);

        // 测试表达式
        Func<int, bool> compiledLambda = lambda.Compile();
        Console.WriteLine(compiledLambda(10)); // 输出 True
    }
}

1.2.2 动态 LINQ 查询

动态条件构建。

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        var data = new List<int> { 1, 2, 3, 4, 5, 6, 7 };

        // 动态创建查询条件 x => x > 3
        ParameterExpression param = Expression.Parameter(typeof(int), "x");
        Expression body = Expression.GreaterThan(param, Expression.Constant(3));
        Expression<Func<int, bool>> predicate = Expression.Lambda<Func<int, bool>>(body, param);

        // 使用条件过滤数据
        var result = data.AsQueryable().Where(predicate);
        Console.WriteLine(string.Join(", ", result)); // 输出 4, 5, 6, 7
    }
}

1.2.3 常见操作符

  • Expression.Add:加法。
  • Expression.AndAlso:逻辑与。
  • Expression.Equal:相等。
  • Expression.Call:方法调用。

动态生成表达式:

Expression<Func<int, int, int>> addExpression = 
    Expression.Lambda<Func<int, int, int>>(
        Expression.Add(
            Expression.Parameter(typeof(int), "a"),
            Expression.Parameter(typeof(int), "b")
        ),
        Expression.Parameter(typeof(int), "a"),
        Expression.Parameter(typeof(int), "b")
    );

2. IQueryable 的用法

2.1 概述

  • IQueryable<T> 是一个接口,继承自 IEnumerable<T>
  • 它支持 延迟执行表达式树解析
  • 常见的场景是和 ORM(如 Entity Framework)一起使用。

关键点

  • 延迟执行:只有当调用 ToListCountFirst 等终结方法时,查询才会被执行。
  • 表达式树:查询会被解析成表达式树并翻译为数据库查询。

2.2 用法示例

2.2.1 基本查询

using System.Linq;

var numbers = Enumerable.Range(1, 10).AsQueryable();

// 查询大于 5 的数字
var query = numbers.Where(x => x > 5);

// 查询未执行(延迟执行)
Console.WriteLine("Query defined");

// 查询执行
var result = query.ToList();
Console.WriteLine(string.Join(", ", result)); // 输出 6, 7, 8, 9, 10

2.2.2 使用自定义表达式

using System;
using System.Linq;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        var numbers = Enumerable.Range(1, 10).AsQueryable();

        // 动态生成表达式 x => x > 5
        ParameterExpression param = Expression.Parameter(typeof(int), "x");
        Expression body = Expression.GreaterThan(param, Expression.Constant(5));
        Expression<Func<int, bool>> predicate = Expression.Lambda<Func<int, bool>>(body, param);

        // 使用动态表达式查询
        var result = numbers.Where(predicate).ToList();
        Console.WriteLine(string.Join(", ", result)); // 输出 6, 7, 8, 9, 10
    }
}

2.2.3 常见扩展方法

  • 过滤Where
  • 投影Select
  • 排序OrderBy, OrderByDescending
  • 聚合Sum, Count, Max, Min

3. 两者结合的使用

利用 ExpressionIQueryable 实现复杂动态查询。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

class Program
{
    static void Main()
    {
        var data = new List<User>
        {
            new User { Id = 1, Name = "Alice", Age = 25 },
            new User { Id = 2, Name = "Bob", Age = 30 },
            new User { Id = 3, Name = "Charlie", Age = 35 }
        }.AsQueryable();

        // 动态生成条件 x => x.Age > 30
        ParameterExpression param = Expression.Parameter(typeof(User), "x");
        Expression body = Expression.GreaterThan(
            Expression.Property(param, "Age"),
            Expression.Constant(30)
        );
        Expression<Func<User, bool>> predicate = Expression.Lambda<Func<User, bool>>(body, param);

        // 使用动态条件查询
        var result = data.Where(predicate).ToList();
        result.ForEach(x => Console.WriteLine(x.Name)); // 输出 Charlie
    }

    class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

4. 总结

| 特性 | Expression | IQueryable | | ---------------- | ---------------------------------------- | ------------------------------------------ | | 作用 | 表达代码的结构(动态生成和解析表达式树) | 表示可查询的数据源,支持延迟执行和表达式树 | | 主要应用场景 | 动态查询、规则引擎、代码生成 | 数据库查询、LINQ 操作 | | 是否延迟执行 | 不涉及执行 | 支持延迟执行 | | 扩展性 | 用于生成复杂的动态条件 | 可结合 Expression 动态构建查询 |

两者结合,可以实现高效、灵活的查询处理。

版权协议:MIT返回列表