C# Expression是什么 - LINQ to SQL的基石

Expression 是可解析为表达式树的数据结构,用于 LINQ to SQL 等框架将查询翻译为 SQL;而 Func 是直接执行的 IL 代码,无法被分析转换。

>是什么 - linq to sql的基石">

Expression> 是一个表示“可被编译、也可被解析为表达式树”的委托类型,它是 LINQ to SQL(以及 EF 等查询提供程序)实现“延迟翻译成 SQL”的核心机制,不是普通方法调用的封装。

它和普通 Func 的本质区别

普通 Func 是一段可执行的 IL 代码,运行时直接调用;而 Expression> 是一段**可被遍历、分析、转换的数据结构(表达式树)**,编译器会把它生成为 Expression.ConstantExpression.CallExpression.Lambda 等节点对象,而非机器码。

  • Func f = () => DateTime.Now.Year + 1; → 运行时立刻算出一个整数
  • Expression> e = () => DateTime.Now.Year + 1; → 得到一棵树:根是 Lambda,子节点是 Call(Now)、MemberAccess(Year)、Constant(1)、Add……

为什么 LINQ to SQL 靠它工作

LINQ 查询(如 db.Users.Where(u => u.Age > 18 && u.City == "Beijing"))中的 u => ... 必须是 Expression>,这样查询提供程序才能:

  • 递归遍历表达式树,识别出字段名(AgeCity)、操作符(>==)、常量值(18"Beijing"
  • 把它们映射成对应数据库的语法,生成类似 WHERE [Age] > 18 AND [City] = 'Beijing' 的 SQL
  • 跳过不支持的操作(比如 u.Name.ToUpper() 若数据库无对应函数,就可能报错或客户端求值)

你不能随便混用 Expression 和 Func

Expression> 当作委托直接调用会失败——它不是可执行体。必须先调用 .Compile() 才能转成真正的 Func

  • Expression> expr = () => 42;
  • int result = expr.Compile()(); // ✅ 先编译再调用
  • int result = expr(); // ❌ 编译不过:Expression 不支持直接调用

简单看一眼表达式树长什么样

这段代码:

Expression> e = () => "Hello".Length.ToString();

实际构建出的树大致包含:
Lambda 节点 → Call 节点(ToString)→ MemberAccess 节点(Length)→ Constant 节点("Hello")
正是这种结构,让框架能“读懂”你的意图,而不是只看到一个黑盒函数。

基本上就这些。理解 Expression 不是为了手写树,而是明白为什么 .Where(x => x.Id == id) 能变 SQL,而 .Where(x => MyHelper.IsValid(x)) 却不行——后者是 Func,没法被翻译。