
C#에서 대리자를 사용해서 코드를 짜다 보면 이런 생각이 들 때가 있습니다.
"이
List.Sort()에 전달할 비교 로직은 간단하고, 여기서 한 번만 쓸 건데...
CompareProductsByName같은 거창한 이름의 메서드를 클래스 어딘가에 만들어야 할까?"
마치 간단한 메모를 위해 새 노트를 펴는 것처럼 번거롭게 느껴질 때가 있죠.
그래서 C# 2.0부터 익명 메서드(Anonymous Method)가 도입되었습니다.
이름 그대로, 이름 없이 바로 그 자리에서 만들어 대리자에 할당하는 메서드입니다.
익명 메서드는 delegate키워드를 사용하여 메서드의 본문을
코드 중간에 직접 작성하는 방식입니다. 이를 통해 코드의 가독성을 높이고,
단발성으로 사용되는 작은 메서드들이 클래스 내에 흩어지는 것을 방지할 수 있습니다.
숫자 리스트에서 짝수만 골라내는 코드를 작성해 봅시다.
List<T>.FindAll()메서드는 조건에 맞는 요소를 찾아주는
Predicate<T>대리자를 매개변수로 받습니다.
public class TraditionalWay
{
// 1. Predicate<int> 대리자에 할당하기 위해 별도의 메서드를 선언해야 함
public bool IsEven(int number)
{
return number % 2 == 0;
}
public void FindEvenNumbers()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 2. 미리 정의된 메서드를 대리자 인스턴스로 만들어 전달
Predicate<int> isEvenPredicate = new Predicate<int>(IsEven);
List<int> evenNumbers = numbers.FindAll(isEvenPredicate);
}
}
IsEven이라는 간단한 기능을 위해 별도의 메서드를 만드는 것은 번거롭게 느껴집니다.
이제 익명 메서드를 사용해 봅시다. IsEven메서드를
따로 만들 필요 없이, 필요한 그 자리에서 즉시 정의할 수 있습니다.
static void FindEvenNumbers()
{
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 'IsEven' 메서드 없이, delegate 키워드로 그 자리에서 즉시 메서드를 정의!
List<int> evenNumbers = numbers.FindAll(
delegate (int number) // 매개변수 선언
{
return number % 2 == 0; // 메서드 본문
}
);
}
IsEven메서드가 사라져서 코드가 훨씬 간결해지고, 로직이 사용되는 위치가 명확해졌습니다.
익명 메서드(Anonymous Method)의 강력한 기능 중 하나는 자신이 선언된 위치의
외부 변수에 접근할 수 있다는 것입니다. 이를 클로저(Closure)라고 합니다.
static void UseClosure()
{
int limit = 5; // 외부 변수
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
// 익명 메서드 안에서 외부 변수인 'limit'을 사용!
List<int> numbersUnderLimit = numbers.FindAll(
delegate (int number)
{
return number < limit;
}
);
// numbersUnderLimit에는 1, 2, 3, 4가 들어있음
}
익명 메서드는 limit이라는 변수를 직접 가지고 있지 않지만,
자신이 생성된 UseClosure메서드의 limit변수를 '캡처'하여 사용할 수 있습니다.
C# 3.0에서 람다 표현식(Lambda Expression)이 등장했습니다.
람다 표현식은 익명 메서드를 훨씬 더 간결하게 표현하는 방법이며,
현대 C# 코드에서는 익명 메서드보다 람다 표현식을 많이 사용합니다.
=>(goes to) 연산자를 사용하여 (입력) => (출력)형태로 표현합니다.
List<int> numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// 1. 익명 메서드 버전
List<int> evenNumbers1 = numbers.FindAll(
delegate (int number) { return number % 2 == 0; }
);
// 2. 람다 표현식 버전 (최종 진화!)
// "number가 주어지면(goest to) number % 2 == 0 결과를 반환하라"
List<int> evenNumbers2 = numbers.FindAll(number => number % 2 == 0);
익명 메서드는 이름 있는 메서드의 번거로움을 해결하기 위해 등장했으며,
C# 3.0에서 람다 표현식이라는 더 발전된 형태로 진화했습니다.
| 구분 | 이름 있는 메서드 | 익명 메서드 | 람다 표현식 (권장) |
|---|---|---|---|
| 재사용성 | 높음 | 낮음 (일회성) | 낮음 (일회성) |
| 간결성 | 낮음 | 중간 | 높음 |
| 핵심 | 재사용 가능한 로직 | 즉석에서 만드는 일회용 로직 | 익명 메서드의 발전된 형태 |