C# 表达式树详解

总目录


前言

在 C# 中,表达式树(Expression Trees)是一种强大的特性,允许开发者将代码表示为数据结构。这使得我们可以在运行时动态地创建和操作代码逻辑,广泛应用于 LINQ 查询、动态方法生成以及反射等领域。本文将深入探讨 C# 表达式树的创建、操作和应用场景。


一、什么是表达式树?

1. 定义

表达式树是一种树状数据结构,将代码表示为一棵树,其中每个节点代表一个操作或数据(如属性访问、方法调用、运算等)。例如,表达式 x + y 可拆解为三个节点:参数 x、参数 y 和加法运算符。

在 C# 中,表达式树由 System.Linq.Expressions 命名空间中的类来表示。表达式树在C#中广泛应用于动态LINQ查询、动态编译等领域。

表达式树是一种数据结构,用于表示代码的逻辑结构(代码中的逻辑和运算)。与普通的委托不同,表达式树不是直接执行代码,而是将其转换为一个可查询和操作的对象模型。这使得我们可以动态地构建、分析和修改代码逻辑。

2. 表达式树的基本组件

  • Expression:表示表达式树的根节点或子表达式。
    • ParameterExpression:表示方法的参数。
    • MemberExpression:表示对对象成员(如属性或字段)的访问。
    • MethodCallExpression:表示对方法的调用。
    • BinaryExpression:表示二元运算(如加法、比较等)。
    • UnaryExpression:表示一元运算(如取反、递增等)。
    • ConstantExpression:表示常量值。
    • LambdaExpression:表示Lambda表达式主体。

2. 与委托和 Lambda 的区别

特性 表达式树 委托
表现形式 可分析的树结构 编译后的IL指令
运行时行为 可动态修改和重组 固定不可变
主要用途 代码生成、动态查询 直接方法调用
执行方式 需编译为委托后执行 直接调用

委托:编译时确定的函数指针,直接执行代码。
Lambda 表达式:可隐式转换为委托或表达式树。
表达式树:将代码逻辑存储为数据结构,支持运行时动态解析和修改。

3. 核心特性

不可变性:创建后无法修改,每次操作生成新树。
可编译性:通过 Compile() 方法生成委托执行。
高效性:相比反射,编译后的表达式树性能接近原生代码。

4. 表达式树的组成部分

一个典型的表达式树包含以下几个部分:

  • 参数:使用 ParameterExpression 定义lambda表达式的参数。
  • 主体:表达式树的主体可以是单一的表达式或多个表达式的组合,例如二元表达式 BinaryExpression 用于表示加法、乘法等操作。
  • lambda表达式:将参数和主体组合成一个lambda表达式,使用 Expression.Lambda 方法创建。

二、表达式树构建方式

1. 通过Lambda自动转换

Expression<Func<int, bool>> expr = num => num > 10 && num < 20;
public class Program
{
   
   
    public static void Main()
    {
   
   
        Expression<Func<int, bool>> expr = num => num > 10 && num < 20;
        Console.WriteLine(expr.ToString()); //输出:num => ((num > 10) AndAlso (num < 20))

        //编译并执行表达式树
        Func<int, bool> func = expr.Compile();        
        Console.WriteLine(func.Invoke(18)); //输出:True
    }
}

2. 手动构建表达式树

1)创建简单的表达式树

示例 1

表达式树通常使用 System.Linq.Expressions 命名空间中的类来构建。以下是一个简单的例子,展示如何创建一个基本的表达式树:

using System;
using System.Linq.Expressions;

public class Program
{
   
   
    public static void Main()
    {
   
   
        // 创建参数表达式 x
        ParameterExpression param = Expression.Parameter(typeof(int), "x");

        // 创建常量表达式 5
        ConstantExpression five = Expression.Constant(5, typeof(int));

        // 创建二元表达式 x + 5
        BinaryExpression add = Expression.Add(param, five);

        // 创建表达式树 x => (x + 5)
        Expression<Func<int, int>> expressionTree = Expression.Lambda<Func<int, int>>(add, param);
        Console.WriteLine(expressionTree);  // 输出: x => (x + 5)

        // 编译并执行表达式树
        Func<int, int> compiledFunc = expressionTree.Compile();
        Console.WriteLine(compiledFunc(10)); // 输出: 15
    }
}
示例 2

以下示例展示了如何创建一个简单的表达式树,该树表示两个数相加的表达式:

public class Program
{
   
   
    public static void Main()
    {
   
   
        // 创建参数表达式
        ParameterExpression a = Expression.Parameter(typeof(int), "a");
        ParameterExpression b = Expression.Parameter(typeof(int), "b");

        // 创建加法表达式
        BinaryExpression add = Expression.Add(a, b);

        // 创建 lambda 表达式
        Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(add, a, b);
        Console.WriteLine(lambda);  // 输出:(a, b) => (a + b)

        // 编译并调用表达式树
        Func<int, int, int> func = lambda.Compile();
        int result = func(2, 3);
        Console.WriteLine($"Result: {
     
     result}"); // 输出: Result: 5
    }
}

2)构建复杂的表达式树

除了简单的算术运算,我们还可以构建更复杂的表达式树,例如条件判断、方法调用等。

示例1:基本组合
using System;
using System.Linq.Expressions;
public class Program
{
   
   
    public static void Main()
    {
   
   
        // 定义参数
        ParameterExpression x = Expression.Parameter(typeof(int), "x");
        // 创建表达式:x * 2
        BinaryExpression multiply = Expression.Multiply(x, Expression.Constant(2));
        // 创建表达式:x * 2 + 3
        BinaryExpression add = Expression.Add(multiply, Expression.Constant(3));
        // 创建lambda表达式
        Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(add, x);
        // 输出lambda表达式
        Console.WriteLine(lambda); // 输出: x => (x * 2 + 3)
        // 编译lambda表达式
        Func<int, int> compiledLambda = lambda.Compile();
        // 执行编译后的lambda表达式
        int result = compiledLambda(5);
        Console.WriteLine($"Result of compiled lambda: {
     
     result}"); // 输出: 13
    }
}
示例2: 条件判断

下面的例子展示了如何构建一个包含条件判断的表达式树:

using System;
using System.Linq.Expressions;

public class Program
{
   
   
    public static void Main()
    {
   
   
        // 创建参数表达式 x
        ParameterExpression param = Expression.Parameter(typeof(int), "x");

        // 创建常量表达式 10
        ConstantExpression ten = Expression.Constant(10, typeof(int));

        // 创建条件表达式 x > 10
        BinaryExpression greaterThan = Expression.GreaterThan(param, ten);

        // 创建 if-true 表达式 x * 2
        BinaryExpression trueResult = Expression.Multiply(param, Expression.Constant(2, typeof(int)));

        // 创建 if-false 表达式 x - 1
        BinaryExpression falseResult = Expression.
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鲤籽鲲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值