首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計疑難解答

C# Expression<Func<T, bool>> vs Func<T, bool>:IQueryable 與 IEnumerable 的分水嶺

     編輯:程式設計疑難解答

在 LINQ 查詢中,Expression<Func<T, bool>> (表達式樹) 與 Func<T, bool> (委派) 的選擇,直接決定查詢是在 **資料庫端執行** 還是 **記憶體中執行**。

核心差異

特性Expression<Func<T,bool>>Func<T,bool>
本質表達式樹 (資料結構,可序列化、可分析)編譯後的 IL 程式碼 (黑盒委派)
適用介面IQueryable<T> (Entity Framework, LINQ to SQL)IEnumerable<T> (LINQ to Objects)
執行位置翻譯為 SQL 在資料庫引擎執行在應用程式記憶體中逐列執行
效能可利用索引、只傳回所需列、網路傳輸少需先把全表拉到記憶體再篩選,極慢
支援運算受限於 SQL 轉譯能力 (如不支援某些 C# 方法)支援任意 C# 程式碼

實務範例

// ✅ 正確:Expression,EF Core 翻譯成 WHERE name LIKE '%abc%'
var users = dbContext.Users.Where(u => u.Name.Contains("abc")).ToList();

// ❌ 錯誤:Func,先載入全表 Users 再在記憶體篩選
Func<User, bool> predicate = u => u.Name.Contains("abc");
var users = dbContext.Users.Where(predicate).ToList(); // 全表掃描!

// ✅ 正確:動態建構 Expression
var param = Expression.Parameter(typeof(User), "u");
var prop = Expression.Property(param, "Name");
var constVal = Expression.Constant("abc");
var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var call = Expression.Call(prop, method, constVal);
var lambda = Expression.Lambda<Func<User, bool>>(call, param);
var users = dbContext.Users.Where(lambda).ToList();

何時用 Func?

  • 資料已在記憶體 (List<T>, Array, 已 .ToList() 的結果)。
  • 邏輯包含無法翻譯為 SQL 的操作 (如自訂方法、複雜演算、外部 API 呼叫)。
  • 本地集合運算 (Enumerable.Where)。

避坑指南

  • 永遠對 IQueryable 使用 lambda 直接傳遞,不要先存入 Func 變數。
  • 動態查詢條件時,使用 PredicateBuilder 或手工組裝 Expression,保持可翻譯性。
  • 開發階段開啟 EF Core 日誌 (LogTo),觀察生成 SQL 確認是否下推。

記住:**Expression = 可翻譯 = 下推資料庫 = 高效**;**Func = 黑盒 = 記憶體篩選 = 低效**。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved