C#运算符表达式树构建指南:从算术到逻辑的完整映射
在 C# 开发中,将标准运算符转换为可执行代码通常依赖表达式树(Expression Trees)。通过 System.Linq.Expressions 命名空间中的各类静态方法,我们可以将算术、关系和逻辑等操作抽象为 AST 节点,进而通过 Expression.Lambda 生成 Func 或 Action 委托并编译执行。本文将详细演示五类核心运算符的使用方式。
准备条件与基础类型
处理表达式树主要分为两种场景:
- 获取计算结果: 使用返回布尔值或数值类型的
Func<T1, T2, TResult>Lambda。 - 执行副作用(如打印): 使用无返回值的
Action<T1, T2>配合BlockExpression包裹多条语句。
对于不同元数的操作,主要对应的表达式类型如下:
UnaryExpression:用于一元运算,如自增/自减、取反。BinaryExpression:用于二元运算,如加减乘除、大小比较。
第1步:算术运算符(加减乘除与取模)
第一步:基础加法与溢出检查
普通加法直接使用 Expression.Add。当需要防止整数溢出时,可使用 AddChecked。
// 定义参数 a=100, b=200
ParameterExpression a = Expression.Parameter(typeof(int), "a");
ParameterExpression b = Expression.Parameter(typeof(int), "b");
// 构建 ab = a + b 节点
BinaryExpression addExp = Expression.Add(a, b);
// 编译为 Func<int, int, int> 以获取结果
Expression<Func<int, int, int>> lambda = Expression.Lambda<Func<int, int, int>>(addExp, a, b);
int result = lambda.Compile()(100, 200); // 输出 300
第二步:使用代码块 (Block) 赋值并执行
如果需要在外部传入变量并在内部赋值(如模拟一个封闭的方法体),需借助 Expression.Block。此时通常使用 Action 类型。
var a = Expression.Parameter(typeof(int), "a");
var b = Expression.Parameter(typeof(int), "b");
// 构建赋值: a=100, b=200
var setA = Expression.Assign(a, Expression.Constant(100));
var setB = Expression.Assign(b, Expression.Constant(200));
// 构建加法及控制台输出
var addResult = Expression.Add(a, b);
var print = Expression.Call(null, typeof(Console).GetMethod("WriteLine", new[] { typeof(int) }), addResult);
// 组合成一个包含多条语句的代码块
var block = Expression.Block(new[] { a, b }, setA, setB, print);
var actionLambda = Expression.Lambda<Action>(block);
actionLambda.Compile()(); // 执行后打印 300
第三步:减法、乘法、除法与取模
C# 表达式树提供了一一对应的方法,其余操作模式与加法完全一致:
- 减法:
Expression.Subtract(带溢出检查:SubtractChecked) - 乘法:
Expression.Multiply(带溢出检查:MultiplyChecked) - 除法:
Expression.Divide - 取模(%):
Expression.Modulo
第2步:自增与自减运算符
自增自减属于一元运算,分为前置(先加后用)和后置(先用后加)。表达式树中的命名遵循英文语义:
- PreIncrementAssign / PreDecrementAssign:对应
++x,--x - PostIncrementAssign / PostDecrementAssign:对应
x++,x--
// 前置自增示例
ParameterExpression x = Expression.Variable(typeof(int), "x");
var preInc = Expression.PreIncrementAssign(x);
var assignX = Expression.Assign(x, Expression.Constant(5));
var block = Expression.Block(new[] { x }, assignX, preInc);
var func = Expression.Lambda<Func<int>>(block).Compile();
Console.WriteLine(func()); // 输出 6
第3步:关系与逻辑运算符构建
关系运算符:相等与比较
关系运算符主要用于判断,返回 bool 类型:
- 相等 (
==):Expression.Equal(对象引用比较)或Expression.NotEqual表示 != - 大于/小于:
Expression.GreaterThan,Expression.LessThan - 大于等于/小于等于:
Expression.GreaterThanOrEqual,Expression.LessThanOrEqual
逻辑运算符:短路求值
在表达式树中,逻辑运算必须使用专用的短路求值方法:
- 逻辑与 (
&&):Expression.AndAlso。如果左操作数为 false,右操作数不被计算。 - 逻辑或 (
||):Expression.OrElse。如果左操作数为 true,右操作数不被计算。 - 逻辑非 (
!):Expression.Not
ParameterExpression a = Expression.Parameter(typeof(int), "a");
ParameterExpression b = Expression.Parameter(typeof(int), "b");
// 构建逻辑判断: a > 5 || a == b
BinaryExpression gtCondition = Expression.GreaterThan(a, Expression.Constant(5));
BinaryExpression eqCondition = Expression.Equal(a, b);
LogicalExpression orLogic = Expression.OrElse(gtCondition, eqCondition);
var check = Expression.Lambda<Func<int, int, bool>>(orLogic, a, b);
Console.WriteLine(check.Compile()(5, 5)); // 输出 True
第4步:位运算符的应用
针对二进制位级别的操作,使用以下专用方法:
| 符号 | 操作 | 表达式树方法 |
|---|---|---|
| & | 按位与 | Expression.And |
| | | 按位或 | Expression.Or |
| ^ | 按位异或 | Expression.ExclusiveOr |
| ~ | 按位取反 | Expression.OnesComplement |
| << | 左移 | Expression.LeftShift |
| >> | 右移 | Expression.RightShift |
第5步:复合赋值与特殊语法
复合赋值(如 a += 1)使用对应的 ...Assign 方法(例如 Expression.AddAssign)。
关于其他复杂语法:
is关键字转换为:Expression.TypeIs? :(三目运算符) 转换为:Expression.Condition结合Expression.IfThen/Expression.IfTrue等。
总结
通过在 C# 中使用各类 Expression. 前缀的工厂方法,开发者可以将程序逻辑抽象化。这对于 ORM 框架(如 EntityFramework)将 LINQ 查询翻译为 SQL,或者构建高性能的动态规则引擎有着至关重要的作用。以上就是 C# 中使用表达式树操作五类运算符的详细内容,更多关于 C# 表达式树进阶的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













