C#运算符表达式树构建指南:从算术到逻辑的完整映射

远山来客
远山来客
发布时间:2026-10-16 | 9人浏览过
原创

在 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# 表达式树进阶的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表