C# 表达式树实现判断语句:if、switch 与三元运算

追风的人
追风的人
发布时间:2026-10-16 | 8人浏览过
原创

C# 中的判断语句若需动态生成或转换为表达式树(如用于 LINQ Provider 或动态脚本),可通过 System.Linq.Expressions 命名空间完成。本文详细演示了使用 Expression API 实现 if、switch、条件三元及空合并运算的标准写法与执行流程。

环境准备与基础概念

在 .NET 环境中处理表达式树时,需引用 System.Linq.Expressions 命名空间。表达式树本质上是数据的抽象语法树(AST),能够被编译器解析并动态编译为可执行委托。常见的判断语句包括:

  • if 语句:根据布尔表达式的结果选择性执行代码块。
  • if...else 语句:在布尔表达式为 false 时执行备选代码块。
  • switch 语句:将单个变量的值与多个预设值进行匹配。
  • 三元/空合并操作符:简化的条件取值逻辑。

第一步:使用表达式树实现 if 语句

目的:构建一个仅在条件为真时执行某动作的表达式树。Expression.IfThen 方法专门用于无 Else 分支的判断结构。

参数入口与方法:Expression.IfThen(Expression test, Expression ifTrue),其中 test 为判定条件,ifTrue 为条件成立时的动作。以下是标准写法对比:

常规 C# 写法如下:

int a = 10;
int b = 10;
if (a == b)
{
    Console.WriteLine("a == b 为 true,语句被执行");
}

使用表达式树重构后的代码如下:

ParameterExpression a = Expression.Variable(typeof(int), "a");
ParameterExpression b = Expression.Variable(typeof(int), "b");
MethodCallExpression call = Expression.Call(
    null,
    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    Expression.Constant("a == b 为 true,表达式树被执行"));

ConditionalExpression _if = Expression.IfThen(Expression.Equal(a, b),call);

Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(_if,a,b);
lambda.Compile()(10,10);

Console.ReadKey();

编译生成的底层 IL 指令表现为标准的条件分支调用:

.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
    System.Int32 $a,
    System.Int32 $b) {
    .If ($a == $b) {
        .Call System.Console.WriteLine("a == b 为 true,表达式树被执行")
    } .Else {
        .Default(System.Void)
    }
}

第二步:使用表达式树实现 if...else 语句

目的:处理包含两个互斥分支的条件逻辑。使用 Expression.IfThenElse 可精确映射传统 if-else 的结构。

参数入口与方法:Expression.IfThenElse(Expression test, Expression ifTrue, Expression ifFalse),ifFalse 表示条件不满足时的回退行为。

常规 C# 写法如下:

int a = 10;
int b = 11;
if (a == b)
{
    Console.WriteLine("a == b 为 true,此语句被执行");
}
else
{
    Console.WriteLine("a == b 为 false,此语句被执行");
}
Console.ReadKey();

转换为表达式树的代码实现如下:

ParameterExpression a = Expression.Variable(typeof(int), "a");
ParameterExpression b = Expression.Variable(typeof(int), "b");
MethodCallExpression call1 = Expression.Call(
    null,
    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    Expression.Constant("a == b 为 true,此表达式树被执行"));

MethodCallExpression call2 = Expression.Call(
    null,
    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    Expression.Constant("a == b 为 false,此表达式树被执行"));

ConditionalExpression _if = Expression.IfThenElse(Expression.Equal(a, b), call1,call2);

Expression<Action<int, int>> lambda = Expression.Lambda<Action<int, int>>(_if, a, b);
lambda.Compile()(10, 11);

Console.ReadKey();

生成的表达式树结构完整保留了两个分支的逻辑走向:

.Lambda #Lambda1<System.Action`2[System.Int32,System.Int32]>(
    System.Int32 $a,
    System.Int32 $b) {
    .If ($a == $b) {
        .Call System.Console.WriteLine("a == b 为 true,此表达式树被执行")
    } .Else {
        .Call System.Console.WriteLine("a == b 为 false,此表达式树被执行")
    }
}

第三步:构建 switch 表达式的判断逻辑

目的:利用表达式树构建多路分支选择器。相较于嵌套 if,Switch 更适合常量值的快速匹配。

核心类库接口:Expression.Switch 负责组装分支逻辑,其重载形式 Switch(SwitchExpression switchValue, Expression defaultBody, params SwitchCase[] cases) 最为常用。各参数职责明确:switchValue 是触发匹配的变量,defaultBody 是无匹配项时的默认逻辑,cases 数组承载具体的 case 条目。

常规 C# 写法如下:

int a = 2;
switch (a)
{
    case 1:Console.WriteLine("a == 1");break;
    case 2:Console.WriteLine("a == 2");break;
    default:Console.WriteLine("a != 1 && a = 2");
}
Console.ReadKey();

表达式树的等价构建过程需要显式实例化每个 SwitchCase:

ParameterExpression a = Expression.Parameter(typeof(int), "a");
MethodCallExpression _default = Expression.Call(
    null,
    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    Expression.Constant("a != 1 && a = 2"));

SwitchCase case1 = Expression.SwitchCase(
    Expression.Call(null,
    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    Expression.Constant("a == 1")),
    new ConstantExpression[] { Expression.Constant(1) }
    );

SwitchCase case2 = Expression.SwitchCase(
    Expression.Call(null,
    typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }),
    Expression.Constant("a == 2")),
    new ConstantExpression[] { Expression.Constant(2) }
    );

SwitchExpression _switch = Expression.Switch(a, _default, new SwitchCase[] { case1, case2 });
Expression<Action<int>> lambda = Expression.Lambda<Action<int>>(_switch, a);
lambda.Compile()(1);

Console.ReadKey();

观察生成的树形结构,可以注意到尽管在底层 IL 层面没有显式的 break 跳转指令,但表达式的语义结构天然保证了各个 Case 块的独立性。在运行时,表达式树引擎会按照正确的控制流执行,不会出现类似 C/C++ 中因遗忘 break 导致的穿透问题。

对应的表达式树输出:

.Lambda #Lambda1<System.Action`1[System.Int32]>(System.Int32 $a) {
    .Switch ($a) {
    .Case (1):
            .Call System.Console.WriteLine("a == 1")
    .Case (2):
            .Call System.Console.WriteLine("a == 2")
    .Default:
            .Call System.Console.WriteLine("a != 1 && a = 2")
    }
}

第四步:处理空合并(?)与三元条件(?)?

除了显式的语句结构,C# 中还提供了基于操作符的轻量级判断模式,它们同样有对应的表达式树工厂方法支持。

首先是空合并运算符 ??。当左侧表达式不为 null 时返回左侧值,否则计算右侧表达式并返回。对应方法是 BinaryExpression Coalesce(Expression left, Expression right)。

其次是条件三元运算符 ?:(即 a > b ? a : b)。它与 if...else 的构造原理一致,使用的是 ConditionalExpression Condition(Expression test, Expression ifTrue, Expression ifFalse)。由于前文已详细阐述过条件分支的构建,此处省略重复代码,可直接复用 IfThenElse 的逻辑框架来理解三元表达式的 AST 形态。

总结

通过在 C# 代码中直接调用 Expression API,开发者能够在内存中动态组装复杂的判断逻辑。这不仅涵盖了基础的 if-else 嵌套,还支持高效的 switch 分发与紧凑的条件赋值。掌握上述核心类的使用方法,是实现高级动态查询引擎和自定义规则评估器的必备技能。以上就是 C# 判断语句的表达式树实现的详细内容,更多关于 C# 高级特性与表达式树应用的资料请关注本站其它相关文章!

相关标签:

本站声明

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

Python 相关产品和应用

全部下载

专题列表