728x90
    
    
  📘 Chapter 3.3: Expression Tree로 컴파일 타임 코드 생성
✅ 이 챕터에서 배울 것
- Expression Tree란 무엇인가?
 - Func와 Expression<Func<T>> 차이
 - 동적으로 조건 쿼리 만들기
 - 메서드 호출도 Expression으로 표현 가능
 - 실전 예제 – 동적 필터링, 간단한 DSL
 - 리플렉션보다 빠른 이유와 주의점
 
1️⃣ Expression Tree란?
C# 코드를 트리 형태로 표현한 객체 구조
Expression<Func<int, int>> expr = x => x + 1;
이 코드는 실제로 이렇게 분해된다:
- 파라미터 x
 - 연산자 +
 - 상수 1
 
→ 전부 트리 형태로 분해돼서 저장됨
📦 표현식 구조 살펴보기
Expression<Func<int, int>> expr = x => x + 1;
Console.WriteLine(expr.Body);           // (x + 1)
Console.WriteLine(expr.Parameters[0]);  // x
✅ 왜 쓰나?
| 용도 | 설명 | 
|---|---|
| ORM | 쿼리 분석 후 SQL로 변환 (EntityFramework 등) | 
| API 필터 | 조건에 따라 쿼리 자동 생성 | 
| Rule Engine | 규칙을 코드로 저장 후 실행 | 
| 코드 생성기 | 조건에 따라 코드 만들어서 실행 | 
2️⃣ Func vs Expression
Func<int, int> f = x => x + 1;
Expression<Func<int, int>> expr = x => x + 1;
| 항목 | Func | Expression | 
|---|---|---|
| 의미 | 코드 | 코드 + 트리 | 
| 실행 | 즉시 실행 | 해석 또는 컴파일 후 실행 | 
| 용도 | 일반 로직 | ORM, DSL, 분석 등 | 
→ Expression은 "코드의 형태로 존재"하고 분석 가능
3️⃣ Expression Tree 구성 직접 만들기
// x => x * 2 표현 직접 만들기
ParameterExpression param = Expression.Parameter(typeof(int), "x");
ConstantExpression two = Expression.Constant(2);
BinaryExpression body = Expression.Multiply(param, two);
var lambda = Expression.Lambda<Func<int, int>>(body, param);
Console.WriteLine(lambda); // x => (x * 2)
Console.WriteLine(lambda.Compile()(10)); // 20
➡️ 이렇게 직접 트리를 만들어서 런타임에 "코드를 조립" 가능
4️⃣ 실전: 조건식 필터링
public class Product
{
    public string Name { get; set; }
    public int Price { get; set; }
}
✅ "Price > 10000" 조건식 생성
ParameterExpression param = Expression.Parameter(typeof(Product), "p");
MemberExpression priceProp = Expression.Property(param, "Price");
ConstantExpression priceValue = Expression.Constant(10000);
BinaryExpression body = Expression.GreaterThan(priceProp, priceValue);
var lambda = Expression.Lambda<Func<Product, bool>>(body, param);
var list = new List<Product>
{
    new Product { Name = "노트북", Price = 12000 },
    new Product { Name = "연필", Price = 500 }
};
var filtered = list.Where(lambda.Compile()).ToList();
✅ 결과: "노트북"만 남는다!
5️⃣ 메서드 호출도 가능
MethodInfo containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
ParameterExpression param = Expression.Parameter(typeof(Product), "p");
MemberExpression nameProp = Expression.Property(param, "Name");
ConstantExpression keyword = Expression.Constant("북");
MethodCallExpression body = Expression.Call(nameProp, containsMethod, keyword);
var lambda = Expression.Lambda<Func<Product, bool>>(body, param);
→ p => p.Name.Contains("북") 을 표현한 Expression
6️⃣ 리플렉션보다 빠른 이유
| 항목 | Reflection | Expression Tree | 
|---|---|---|
| 속성 호출 | Invoke 사용 → 느림 | 미리 컴파일 → 빠름 | 
| 메모리 | 더 사용 | 덜 사용 | 
| 예외 발생 | 런타임 많음 | 비교적 안정적 | 
✅ 정리 요약
| 항목 | 요약 | 
|---|---|
| Expression Tree | 코드를 트리 형태로 표현, 조작 가능 | 
| Func vs Expression | 전자는 실행, 후자는 구조 분석용 | 
| 실무 활용 | ORM, 조건 필터, DSL, 코드 생성 | 
| 장점 | 리플렉션보다 빠르고 안전 | 
| 한계 | 너무 복잡한 로직 구성은 어려움 | 
📢 다음 챕터 예고 🎓
| Chapter | 주제 | 
|---|---|
| 3.4 | 고급 LINQ 커스터마이징, 쿼리 최적화 | 
728x90