ExpressionExtensions 提供多種 Lambda Expression 的組合、參數操作與擴充功能,讓你能更靈活地進行動態查詢條件組合、參數綁定、參數擴展、參數合併與條件反向等操作。
這些功能特別適合用於 LINQ、EF Core 等需要動態產生查詢條件的情境,讓程式碼更簡潔、可讀性更高,也更容易維護。
將多個條件以 AND(&&)邏輯合併為單一 Lambda 表達式。
Expression<Func<int, bool>> expr1 = x => x > 0;
Expression<Func<int, bool>> expr2 = x => x < 100;
var combined = expr1.AndAlso(expr2);
// x => ((x > 0) && (x < 100))
Console.WriteLine(combined.Compile()(50)); // True
Console.WriteLine(combined.Compile()(150)); // FalseExpression<Func<int, string, bool>> expr3 = (x, y) => x > 0;
Expression<Func<int, string, bool>> expr4 = (x, y) => y.Length > 2;
var combined2 = expr3.AndAlso(expr4);
// (x, y) => ((x > 0) && (y.Length > 2))將多個條件以 OR(||)邏輯合併為單一 Lambda 表達式。
Expression<Func<int, bool>> expr1 = x => x < 0;
Expression<Func<int, bool>> expr2 = x => x > 100;
var combined = expr1.OrElse(expr2);
// x => ((x < 0) || (x > 100))
Console.WriteLine(combined.Compile()(-5)); // True
Console.WriteLine(combined.Compile()(50)); // FalseExpression<Func<int, string, bool>> expr3 = (x, y) => x < 0;
Expression<Func<int, string, bool>> expr4 = (x, y) => y == "ok";
var combined2 = expr3.OrElse(expr4);
// (x, y) => ((x < 0) || (y == "ok"))產生原 Lambda 條件的邏輯相反(NOT)表達式。
Expression<Func<int, bool>> expr = x => x > 0;
var notExpr = expr.Not();
// x => Not(x > 0)
Console.WriteLine(notExpr.Compile()(1)); // False
Console.WriteLine(notExpr.Compile()(-1)); // TrueExpression<Func<int, string, bool>> expr2 = (x, y) => y.Length == x;
var not2 = expr2.Not();
// (x, y) => Not(y.Length == x)將 Lambda 的最後一個參數綁定為指定值,產生參數數量更少的新 Lambda(部分應用)。
Expression<Func<int, int, bool>> expr = (a, b) => a + b > 10;
var bound = expr.Bind(5);
// a => (a + 5) > 10
Console.WriteLine(bound.Compile()(6)); // True
Console.WriteLine(bound.Compile()(3)); // FalseExpression<Func<int, int, string, bool>> expr2 = (a, b, c) => a.ToString() == c && b > 0;
var bound2 = expr2.Bind("abc");
// (a, b) => (a.ToString() == "abc") && b > 0將 Lambda 參數數量擴展(增加一個參數),但主體不會用到新參數,常用於參數對齊。
Expression<Func<int, bool>> expr = x => x > 10;
var expanded = expr.Expand<int, string>();
// (x, x_1) => x > 10
Console.WriteLine(expanded.Compile()(15, "")); // True
Console.WriteLine(expanded.Compile()(5, "")); // FalseExpression<Func<int, int, bool>> expr2 = (x, y) => x > y;
var expanded2 = expr2.Expand<int, int, int>();
// (x, y, y_2) => x > y將 Lambda 的最後兩個參數合併為同一個(例如 y 變成 x),產生參數數量更少的新 Lambda。
Expression<Func<int, int, bool>> expr = (x, y) => x == y;
var merged = expr.Merge();
// x => x == x
Console.WriteLine(merged.Compile()(50)); // True
Console.WriteLine(merged.Compile()(10)); // TrueExpression<Func<int, string, string, bool>> expr2 = (a, b, c) => b == c && a.ToString() == b;
var merged2 = expr2.Merge<int, string>();
// (a, b) => b == b && a.ToString() == b結合 ExpressionExtensions 與 Entity Framework Core(以 SQL Server 為例),實現動態查詢條件組合,並印出 SQL、參數與查詢結果:
using System;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;
using ExpressionExtensions;
public class Person
{
public int Id { get; set; }
public string Name { get; set; } = "";
public int Age { get; set; }
}
public class SampleDbContext : DbContext
{
public DbSet<Person> People => Set<Person>();
private readonly string _connectionString;
public SampleDbContext(string connectionString)
{
_connectionString = connectionString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder.UseSqlServer(_connectionString);
}
class Program
{
static void Main()
{
var connectionString = "Server=(localdb)\\mssqllocaldb;Database=TestDb;Trusted_Connection=True;";
using var db = new SampleDbContext(connectionString);
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
db.People.AddRange(
new Person { Name = "Alice", Age = 20 },
new Person { Name = "Bob", Age = 30 },
new Person { Name = "Carol", Age = 40 }
);
db.SaveChanges();
// 建立條件運算式
Expression<Func<Person, bool>> ageGt20 = p => p.Age > 20;
Expression<Func<Person, bool>> nameIsBob = p => p.Name == "Bob";
var combined = ageGt20.AndAlso(nameIsBob);
// 查詢
var query = db.People.Where(combined);
// 印出 SQL 及參數
Console.WriteLine(query.ToQueryString());
// 執行查詢並印出結果
var result = query.ToList();
foreach (var person in result)
{
Console.WriteLine($"{person.Name} ({person.Age})");
}
// 輸出:
// SELECT [p].[Id], [p].[Name], [p].[Age]
// FROM [People] AS [p]
// WHERE ([p].[Age] > 20) AND ([p].[Name] = N'Bob')
// Bob (30)
}
}