表达式树(一)

本文深入探讨C#中的表达式树,它是代码的树形表示形式,用于动态修改执行代码、实现LINQ查询及动态语言与.NET Framework的互操作。通过C#编译器或直接使用API创建表达式树,并学习如何解析、修改和编译表达式树。示例展示了如何创建和使用表达式树进行条件判断、循环和计算等操作。
摘要由CSDN通过智能技术生成

表达式树 (C#)

表达式树以树形数据结构表示代码,其中每一个节点都是一种表达式,比如方法调用和 x < y 这样的二元运算等。

你可以对表达式树中的代码进行编辑和运算。 这样能够动态修改可执行代码、在不同数据库中执行 LINQ 查询以及创建动态查询。 有关 LINQ 中表达式树的详细信息,请参阅如何:使用表达式树生成动态查询 (C#)

表达式树还能用于动态语言运行时 (DLR) 以提供动态语言和 .NET Framework 之间的互操作性,同时保证编译器编写员能够发射表达式树而非 Microsoft 中间语言 (MSIL)。 有关 DLR 的详细信息,请参阅动态语言运行时概述

你可以基于匿名 lambda 表达式通过 C# 或者 Visual Basic 编译器创建表达式树,或者通过 xref:System.Linq.Expressions 名称空间手动创建。

根据 Lambda 表达式创建表达式树

若 lambda 表达式被分配给 System.Linq.Expressions.Expression类型的变量,则编译器可以发射代码以创建表示该 lambda 表达式的表达式树。

C# 编译器只能从表达式 Lambda(或单行 Lambda)生成表达式树。 它无法解析语句 lambda (或多行 lambda)

下列代码示例展示如何通过 C# 编译器创建表示 Lambda 表达式 num => num < 5 的表达式树。

Expression<Func<int, bool>> lambda = num => num < 5;  

通过 API 创建表达式树

通过 API 创建表达式树需要使用 System.Linq.Expressions.Expression类。 类包含创建特定类型表达式树节点的静态工厂方法,比如表示参数变量的 System.Linq.Expressions.ParameterExpression,或者是表示方法调用的 System.Linq.Expressions.MethodCallExpressionSystem.Linq.Expressions.ParameterExpression 名称空间还解释了 System.Linq.Expressions.MethodCallExpression、System.Linq.Expressions和另一种具体表达式类型。 这些类型来源于抽象类型 System.Linq.Expressions.Expression

下列代码示例展示如何使用 API 创建表示 Lambda 表达式 num => num < 5 的表达式树。

// Add the following using directive to your code file:  
// using System.Linq.Expressions;  
  
// Manually build the expression tree for   
// the lambda expression num => num < 5.  
ParameterExpression numParam = Expression.Parameter(typeof(int), "num");  
ConstantExpression five = Expression.Constant(5, typeof(int));  
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);  
Expression<Func<int, bool>> lambda1 =  
    Expression.Lambda<Func<int, bool>>(  
        numLessThanFive,  
        new ParameterExpression[] { numParam });  

在 .NET Framework 4 或更高版本中,表达式树 API 还支持赋值表达式和控制流表达式,例如循环、条件块和 try-catch 块等。 相对于通过 C# 编译器和 Lambda 表达式创建表达式树,还可利用 API 创建更加复杂的表达式树。 下列示例展示如何创建计算数字阶乘的表达式树。

// Creating a parameter expression.  
ParameterExpression value = Expression.Parameter(typeof(int), "value");  
  
// Creating an expression to hold a local variable.   
ParameterExpression result = Expression.Parameter(typeof(int), "result");  
  
// Creating a label to jump to from a loop.  
LabelTarget label = Expression.Label(typeof(int));  
  
// Creating a method body.  
BlockExpression block = Expression.Block(  
    // Adding a local variable.  
    new[] { result },  
    // Assigning a constant to a local variable: result = 1  
    Expression.Assign(result, Expression.Constant(1)),  
    // Adding a loop.  
        Expression.Loop(  
    // Adding a conditional block into the loop.  
           Expression.IfThenElse(  
    // Condition: value > 1  
               Expression.GreaterThan(value, Expression.Constant(1)),  
    // If true: result *= value --  
               Expression.MultiplyAssign(result,  
                   Expression.PostDecrementAssign(value)),  
    // If false, exit the loop and go to the label.  
               Expression.Break(label, result)  
           ),  
    // Label to jump to.  
       label  
    )  
);  
  
// Compile and execute an expression tree.  
int factorial = Expression.Lambda<Func<int, int>>(block, value).Compile()(5);  
  
Console.WriteLine(factorial);  
// Prints 120.  

解析表达式树

下列代码示例展示如何分解表示 Lambda 表达式 num => num < 5 的表达式树。

// Add the following using directive to your code file:  
// using System.Linq.Expressions;  
  
// Create an expression tree.  
Expression<Func<int, bool>> exprTree = num => num < 5;  
  
// Decompose the expression tree.  
ParameterExpression param = (ParameterExpression)exprTree.Parameters[0];  
BinaryExpression operation = (BinaryExpression)exprTree.Body;  
ParameterExpression left = (ParameterExpression)operation.Left;  
ConstantExpression right = (ConstantExpression)operation.Right;  
  
Console.WriteLine("Decomposed expression: {0} => {1} {2} {3}",  
                  param.Name, left.Name, operation.NodeType, right.Value);  
  
// This code produces the following output:  
  
// Decomposed expression: num => num LessThan 5  

表达式树永久性

表达式树应具有永久性。 这意味着如果你想修改某个表达式树,则必须复制该表达式树然后替换其中的节点来创建一个新的表达式树。 你可以使用表达式树访问者遍历现有表达式树。

编译表达式树

System.Linq.Expressions.Expression 类型提供了 System.Linq.Expressions.Expression.Compile 方法以将表达式树表示的代码编译成可执行委托。

下列代码示例展示如何编译表达式树并运行结果代码。

// Creating an expression tree.  
Expression<Func<int, bool>> expr = num => num < 5;  
  
// Compiling the expression tree into a delegate.  
Func<int, bool> result = expr.Compile();  
  
// Invoking the delegate and writing the result to the console.  
Console.WriteLine(result(4));  
  
// Prints True.  
  
// You can also use simplified syntax  
// to compile and run an expression tree.  
// The following line can replace two previous statements.  
Console.WriteLine(expr.Compile()(4));  
  
// Also prints True.  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值