람다는 한 줄로 말하면 이렇게 볼 수 있다.
람다식 = 어딘가에 넘겨줄 “작은 메서드 조각”을 코드 안에서 바로 적는 문법
그리고 이 “작은 메서드”를 담는 그릇이 바로 델리게이트 타입(delegate)이다.
// 전용 델리게이트 타입 선언
delegate bool NumberTest(int n);
class Program
{
static void Main()
{
NumberTest isEven = n => n % 2 == 0; // 람다를 델리게이트에 담음
NumberTest isOdd = n => n % 2 != 0;
Console.WriteLine(isEven(10)); // true
Console.WriteLine(isOdd(10)); // false
}
}
delegate bool NumberTest(int n);
→ “int 하나 받아서 bool을 반환하는 함수를 담는 전용 타입”n => n % 2 == 0
→ 이 부분이 바로 “익명 메서드 본문” 역할을 하는 람다식NumberTest isEven = ...
→ “이 델리게이트 변수는 이 람다 메서드를 가리킨다”는 뜻
정리하면, 람다 자체는 익명 메서드이고,
그걸 담는 타입이 델리게이트라고 보면 된다.
어떤 공통 함수를 만들고, “조건”만 바꿔가며 쓰고 싶을 때 전용 델리게이트가 유용하다.
delegate bool NumberTest(int n);
static int Count(int[] numbers, NumberTest test)
{
int count = 0;
foreach (int n in numbers)
{
if (test(n))
count++;
}
return count;
}
사용 예:
int[] arr = { 1, 2, 3, 4, 5, 6 };
// 1) 일반 메서드 전달
static bool IsEven(int n) => n % 2 == 0;
int evenCount1 = Count(arr, IsEven);
// 2) 람다식으로 바로 조건 전달
int evenCount2 = Count(arr, n => n % 2 == 0);
int overThree = Count(arr, n => n > 3);
Count는 “배열을 돌면서 조건에 맞는 것만 세는 공통 함수”NumberTest 델리게이트에 람다를 넣어 바꿔준다
이 패턴이 확장된 게 Predicate<T>, Comparison<T> 같은 델리게이트들이다.
매번 delegate ...를 선언하기 귀찮으니까, .NET에서는 미리 여러 델리게이트 타입을 만들어두었다.
Action, Action<T>, Action<T1,T2,...> → 반환값 없음Func<T1,...,TResult> → 마지막 타입이 반환형Predicate<T> → 실질적으로 Func<T,bool>과 같은 역할예를 들어, 이런 전용 델리게이트를:
delegate bool NumberTest(int n);
굳이 안 만들고 이렇게도 쓸 수 있다:
Func<int, bool> test1 = n => n % 2 == 0;
Predicate<int> test2 = n => n > 10;
요약하면:
delegate bool NumberTest(int n);Func, Action, Predicate<T> 등
두 번째 축은 컬렉션(List, 배열, LINQ)에서 람다를 어떻게 쓰는지이다.
실무에서는 이 부분에서 람다가 가장 많이 등장한다.
List<T>에는 델리게이트를 받는 메서드가 아주 많다.
Find(Predicate<T> match)FindAll(Predicate<T> match)Exists(Predicate<T> match)RemoveAll(Predicate<T> match)Sort(Comparison<T> comparison)ForEach(Action<T> action)모두 “델리게이트 인수”를 받기 때문에, 여기에 람다를 바로 넘겨줄 수 있다.
var list = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// 1) Find: 조건을 만족하는 첫 번째 원소
int firstEven = list.Find(n => n % 2 == 0);
// 2) FindAll: 조건을 만족하는 모든 원소
List<int> evenList = list.FindAll(n => n % 2 == 0);
// 3) Exists: 조건을 만족하는 게 하나라도 있는지
bool hasBig = list.Exists(n => n > 100);
// 4) RemoveAll: 조건을 만족하는 원소 모두 삭제
int removedCount = list.RemoveAll(n => n % 2 == 0);
n => n % 2 == 0 → Predicate<int> 타입에 맞는 람다식var people = new List<(string Name, int Age)>
{
("Kim", 30),
("Lee", 20),
("Park", 40),
};
// 나이 기준 오름차순 정렬
people.Sort((a, b) => a.Age.CompareTo(b.Age));
// 이름 기준 내림차순 정렬
people.Sort((a, b) => string.Compare(b.Name, a.Name, StringComparison.Ordinal));
여기서 (a, b) => ... 부분이 바로 Comparison<T> 델리게이트에 전달되는 람다 메서드이다.
LINQ 확장 메서드들도 결국
“제네릭 메서드 + 델리게이트 인수 + 람다 전달” 구조이다.
대표적인 메서드들:
Where(Func<T, bool>)Select(Func<TSource, TResult>)Any(Func<T, bool>)All(Func<T, bool>)OrderBy(Func<T, TKey>)GroupBy(Func<T, TKey>)var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 짝수만 고르고(Where), 제곱으로 바꾸고(Select), 리스트로 만들기(ToList)
var evenSquares = numbers
.Where(n => n % 2 == 0) // Func<int, bool>
.Select(n => n * n) // Func<int, int>
.ToList(); // List<int>
Where 안의 n => n % 2 == 0 → Func<int,bool> 델리게이트에 들어가는 람다Select 안의 n => n * n → Func<int,int> 델리게이트에 들어가는 람다class Order
{
public string CustomerCode { get; set; }
public decimal Amount { get; set; }
public bool IsCanceled { get; set; }
}
var orders = new List<Order>
{
new Order { CustomerCode = "C001", Amount = 100_000m, IsCanceled = false },
new Order { CustomerCode = "C001", Amount = 50_000m, IsCanceled = true },
new Order { CustomerCode = "C002", Amount = 200_000m, IsCanceled = false },
};
// 1) 취소되지 않은 주문만
var validOrders = orders
.Where(o => !o.IsCanceled)
.ToList();
// 2) 특정 거래처(C001) + 10만원 이상 주문만
var filtered = orders
.Where(o => o.CustomerCode == "C001" && o.Amount >= 100_000m)
.ToList();
// 3) 거래처별 매출 합계
var sumByCustomer = orders
.Where(o => !o.IsCanceled)
.GroupBy(o => o.CustomerCode)
.Select(g => new
{
Customer = g.Key,
Total = g.Sum(o => o.Amount)
})
.ToList();
여기 있는 모든 => 뒤의 코드들이 다 람다 메서드이고,
각각 Func<Order,bool>, Func<Order,string>, Func<Order,decimal> 등의 델리게이트 자리에 들어간다.
delegate bool NumberTest(int n);Func, Action, Predicate<T>, Comparison<T> 등Count, Filter, Process 등)에List<T>의 Find, FindAll, Exists, Sort, RemoveAll, ForEach 등은
모두 델리게이트 인수를 받는다.Where, Select, OrderBy, GroupBy 등은
제네릭 메서드 + Func 델리게이트 + 람다의 조합이다.이 두 관점을 머릿속에 같이 두면,
“람다 = 델리게이트에 들어가는 작은 메서드”
“컬렉션/ LINQ = 그 작은 메서드를 실전에서 쓰는 장소”
이렇게 연결돼서 훨씬 이해하기 쉬워진다.