안녕하세요! 지난 포스팅에서는 델리게이트와 이벤트를 통해 메서드를 변수처럼 다루고, 객체 간에 유연하게 통신하는 방법을 알아봤습니다. 이번에는 델리게이트와 이벤트를 사용할 때 코드를 훨씬 더 간결하고 직관적으로 만들어주는 두 가지 강력한 기능, **익명 메서드(Anonymous Method)**와 **람다식(Lambda Expression)**에 대해 자세히 살펴보겠습니다. 이 둘은 코드를 "즉석에서" 정의하고 전달할 수 있게 해줍니다.
1. 익명 메서드(Anonymous Method): 이름 없는 함수
일반적으로 델리게이트나 이벤트에 할당할 메서드는 별도의 이름을 가진 메서드로 정의해야 했습니다. 하지만 익명 메서드는 이름 없이 바로 그 자리에서 정의하여 델리게이트에 할당할 수 있는 코드 블록입니다. C# 2.0에서 도입되어 코드를 더 간결하게 만들었습니다.
익명 메서드의 특징:
- delegate 키워드 사용: 익명 메서드를 정의할 때 delegate 키워드를 사용합니다.
- 이름 없음: 말 그대로 메서드 이름이 없습니다.
- 즉석 정의: 델리게이트 변수에 할당하거나 이벤트에 등록할 때 바로 그 자리에서 코드를 작성합니다.
- 외부 변수 캡처(Closure): 익명 메서드가 정의된 스코프(영역) 내의 지역 변수들을 사용할 수 있습니다.
익명 메서드 사용 예시:
// 델리게이트 정의 (이전 예시와 동일)
public delegate void MessageDelegate(string message);
public class Notifier
{
public event MessageDelegate OnNotify;
public void DoSomethingAndNotify(string data)
{
Console.WriteLine($"Notifier: 어떤 작업을 수행 중... (데이터: {data})");
// 이벤트 발생
OnNotify?.Invoke($"작업이 완료되었습니다: {data}");
}
}
public class Program
{
public static void Main(string[] args)
{
Notifier notifier = new Notifier();
// 1. 익명 메서드를 사용하여 이벤트 구독
notifier.OnNotify += delegate(string msg) // delegate 키워드로 익명 메서드 시작
{
Console.WriteLine($"[익명 메서드] 알림 받음: {msg}");
};
// 외부 변수 캡처 예시
string prefix = "LOG: ";
notifier.OnNotify += delegate(string msg)
{
Console.WriteLine($"{prefix}{msg}"); // 외부 변수 prefix 사용
};
notifier.DoSomethingAndNotify("핵심 데이터");
/*
출력:
Notifier: 어떤 작업을 수행 중... (데이터: 핵심 데이터)
[익명 메서드] 알림 받음: 작업이 완료되었습니다: 핵심 데이터
LOG: 작업이 완료되었습니다: 핵심 데이터
*/
Console.WriteLine("\n--- 익명 메서드를 델리게이트 변수에 할당 ---");
// 델리게이트 변수에 익명 메서드 할당
MessageDelegate myLogger = delegate(string logMsg)
{
Console.WriteLine($"[MyLogger] {logMsg}");
};
myLogger("이 메시지는 익명 메서드를 통해 출력됩니다."); // [MyLogger] 이 메시지는 익명 메서드를 통해 출력됩니다.
}
}
익명 메서드는 짧고 간단한 로직을 바로 그 자리에서 구현할 때 유용하며, 별도의 이름 있는 메서드를 만들 필요가 없어 코드의 가독성을 높일 수 있습니다.
2. 람다식(Lambda Expression): 익명 메서드의 진화형!
람다식은 C# 3.0에서 LINQ(Language Integrated Query)와 함께 도입된 기능으로, 익명 메서드보다 훨씬 더 간결하고 표현력이 풍부한 문법을 제공합니다. 람다식은 '수학의 람다 계산'에서 영감을 받아, 입력과 출력을 정의하는 '수학 함수'처럼 코드를 표현합니다.
람다식의 핵심 문법: => (go-to 연산자)
람다식은 다음과 같은 형태로 작성됩니다:
([매개변수]) => [식 또는 문장 블록]
- ( ): 매개변수 목록. 매개변수가 하나이면 괄호 생략 가능. 매개변수가 없으면 빈 괄호 () 사용.
- =>: 'go-to' 연산자 또는 '람다 연산자'라고 불립니다. '입력'을 '출력/실행'으로 연결합니다.
- [식 또는 문장 블록]: 람다식이 실행할 코드.
- 식 본문 (Expression Body): 한 줄짜리 표현식인 경우. (예: a + b)
- 문장 블록 (Statement Body): 여러 줄의 코드가 필요한 경우 { } 블록 사용.
람다식 사용 예시:
위의 Notifier 예시를 람다식으로 바꿔보겠습니다.
// 델리게이트 정의 (이전과 동일)
public delegate void MessageDelegate(string message);
public class Notifier
{
public event MessageDelegate OnNotify;
public void DoSomethingAndNotify(string data)
{
Console.WriteLine($"Notifier: 어떤 작업을 수행 중... (데이터: {data})");
OnNotify?.Invoke($"작업이 완료되었습니다: {data}");
}
}
public class Program
{
public static void Main(string[] args)
{
Notifier notifier = new Notifier();
// 1. 람다식을 사용하여 이벤트 구독 (가장 일반적인 형태)
// 매개변수가 하나이므로 괄호 생략 가능: msg =>
notifier.OnNotify += (msg) => Console.WriteLine($"[람다식 1] 알림 받음: {msg}");
// 람다식에서 여러 줄의 코드가 필요한 경우 블록 사용
string suffix = "!!!";
notifier.OnNotify += (msg) => // 외부 변수 suffix 캡처
{
Console.WriteLine($"[람다식 2] {msg}{suffix}");
Console.WriteLine(" - 두 번째 람다 블록 실행");
};
notifier.DoSomethingAndNotify("핵심 데이터");
/*
출력:
Notifier: 어떤 작업을 수행 중... (데이터: 핵심 데이터)
[람다식 1] 알림 받음: 작업이 완료되었습니다: 핵심 데이터
[람다식 2] 작업이 완료되었습니다: 핵심 데이터!!!
- 두 번째 람다 블록 실행
*/
Console.WriteLine("\n--- 람다식을 델리게이트 변수에 할당 (다양한 형태) ---");
// 매개변수가 없는 람다식
Action helloWorld = () => Console.WriteLine("Hello, World from Lambda!");
helloWorld();
// 매개변수가 여러 개인 람다식
Func<int, int, int> addFunc = (x, y) => x + y; // int 두 개 받아 int 반환
Console.WriteLine($"람다 덧셈: {addFunc(7, 3)}"); // 10
// 반환형이 없는 람다식
Action<string> greetAction = name => Console.WriteLine($"안녕하세요, {name}님!");
greetAction("김철수");
// 복잡한 로직을 가진 람다식 (문장 블록)
Func<int, int, string> compareNumbers = (num1, num2) =>
{
if (num1 > num2) return $"{num1}이(가) {num2}보다 큽니다.";
else if (num1 < num2) return $"{num1}이(가) {num2}보다 작습니다.";
else return $"{num1}과 {num2}는 같습니다.";
};
Console.WriteLine(compareNumbers(10, 5)); // 10이(가) 5보다 큽니다.
}
}
람다식은 익명 메서드보다 훨씬 더 간결한 문법을 제공하여, LINQ 쿼리나 이벤트 핸들러 등 짧은 코드 블록을 전달해야 할 때 코드를 매우 깔끔하게 만들어줍니다.
3. 익명 메서드 vs 람다식: 누가 더 좋을까?
- 익명 메서드 (delegate { ... }):
- C# 2.0에서 도입.
- 람다식보다 문법이 더 길지만, 내부적으로는 거의 동일하게 작동합니다.
- 주로 레거시 코드나, 람다식이 너무 복잡해져서 가독성이 떨어질 때 (드물게) 사용될 수 있습니다.
- 람다식 (=>):
- C# 3.0에서 도입. 현대 C# 프로그래밍에서 압도적으로 선호됩니다.
- 훨씬 간결한 문법로 코드의 가독성을 높입니다.
- Func<...>와 Action<...> 같은 제네릭 델리게이트와 완벽하게 어울립니다.
- LINQ 쿼리 표현식의 핵심입니다.
결론적으로, 새로운 코드를 작성할 때는 특별한 이유가 없는 한 람다식을 사용하는 것이 좋습니다. 람다식이 제공하는 간결성과 유연성은 현대 C# 개발에서 생산성을 크게 향상시킵니다.
4. 유니티에서 익명 메서드/람다식 활용하기
유니티는 이벤트 기반 시스템이 많기 때문에, 델리게이트와 람다식은 매우 중요하게 활용됩니다.
4.1. UI 이벤트 핸들링
유니티 UI (UGUI)의 버튼 클릭 이벤트 등에 람다식을 바로 연결할 수 있습니다.
// ButtonHandler.cs
using UnityEngine;
using UnityEngine.UI; // UI 컴포넌트를 사용하기 위해 필요
public class ButtonHandler : MonoBehaviour
{
public Button myButton;
public Text statusText;
void Start()
{
if (myButton != null)
{
// 람다식을 사용하여 버튼 클릭 이벤트에 함수 연결
myButton.onClick.AddListener(() => { // 매개변수가 없으므로 () =>
statusText.text = "버튼이 클릭되었습니다!";
Debug.Log("버튼 클릭!");
PlayClickSound(); // 다른 메서드 호출도 가능
});
// 매개변수가 있는 슬라이더 값 변경 이벤트 (예시)
// Slider slider;
// slider.onValueChanged.AddListener(value => { // 매개변수가 하나이므로 value =>
// Debug.Log("슬라이더 값: " + value);
// });
}
}
void PlayClickSound()
{
// 실제 게임에서는 AudioSource.Play() 등을 호출
Debug.Log("클릭 사운드 재생!");
}
}
따로 OnClickButton() 같은 메서드를 정의하지 않고, 버튼에 기능을 바로 연결할 수 있어 코드가 깔끔해집니다.
4.2. 콜백 함수 전달
비동기 작업(예: 네트워크 통신, 파일 로드 완료) 후에 실행될 콜백 함수를 람다식으로 전달하는 것이 일반적입니다.
// DataLoader.cs
using UnityEngine;
using System; // Action, Func을 위해 필요
public class DataLoader : MonoBehaviour
{
// 데이터를 로드하는 척 하고 콜백을 호출하는 메서드
public void LoadDataFromServer(string url, Action<string> onDataLoaded) // Action<string>은 string 매개변수 하나, 반환값 없는 델리게이트
{
Debug.Log($"서버에서 데이터 로드 시작: {url}");
// 실제로는 비동기 통신 로직
// ... (가상의 딜레이)
string loadedData = $"<데이터 from {url}> 성공적으로 로드됨!";
onDataLoaded?.Invoke(loadedData); // 데이터 로드 완료 후 콜백 호출
}
void Start()
{
// 람다식을 사용하여 데이터 로드 완료 시 실행될 콜백 정의
LoadDataFromServer("http://mygame.com/data", (data) => {
Debug.Log($"[메인 스크립트] 로드된 데이터: {data}");
// 로드된 데이터로 UI 업데이트 또는 게임 로직 처리
if (data.Contains("성공"))
{
Debug.Log("데이터 로드 성공! 게임 시작 준비 완료.");
}
});
}
}
이처럼 Action이나 Func 델리게이트를 매개변수로 받아 람다식을 전달하면, 특정 작업이 완료된 후 수행할 로직을 매우 유연하게 정의할 수 있습니다.
마무리하며: 람다식으로 C# 코드를 더욱 우아하게!
익명 메서드와 람다식은 델리게이트와 이벤트를 활용할 때 코드를 더 간결하고 직관적으로 만들어주는 강력한 문법입니다. 특히 람다식은 현대 C# 개발에서 델리게이트와 함께 가장 많이 사용되는 기능 중 하나이며, LINQ, 비동기 프로그래밍, 유니티 UI 이벤트 등 다양한 분야에서 코드의 표현력과 생산성을 크게 향상시킵니다.
이 두 가지를 잘 활용하면, 여러분의 C# 코드가 더욱 우아하고 관리하기 쉬워질 것입니다.
익명 메서드나 람다식에 대해 더 궁금한 점이 있으시거나, 특정 유니티 상황에서의 활용법에 대해 알고 싶으신가요? 언제든지 질문해주세요!
'C# > C# 문법' 카테고리의 다른 글
| 클래스와 구조체의 차이 (0) | 2025.09.13 |
|---|---|
| 추상 클래스와 인터페이스의 차이 (0) | 2025.09.11 |
| C# 중급 문법 (7) : 델리게이트와 이벤트 (1) | 2025.08.31 |
| C# 중급 문법 (6) : Static에 대해서 (1) | 2025.08.20 |
| C# 중급 문법 (5) : 구조체 (3) | 2025.08.17 |