델리게이트는 메서드를 가리키는 참조형 변수로, 코드의 유연성과 확장성을 높이는 데 유용합니다. 이벤트는 델리게이트를 기반으로 구현되어 객체 간의 상호작용을 간단하고 안전하게 처리할 수 있게 합니다. 이번 글에서는 델리게이트의 개념과 사용법, 익명 메서드와 람다 표현식, 이벤트의 선언과 구독을 다룹니다.
1. 델리게이트의 개념과 사용법
**델리게이트(Delegate)**는 메서드 참조를 저장할 수 있는 타입입니다. 이를 사용하면 메서드를 변수처럼 전달하거나 실행할 수 있습니다. 델리게이트는 함수 포인터와 비슷하지만, C#에서는 타입 안전성과 객체 지향의 특성을 유지합니다.
델리게이트 선언, 초기화, 호출
using System;
// 델리게이트 선언: 반환형과 매개변수가 일치해야 함
delegate void GreetDelegate(string name);
class Program
{
// 델리게이트가 가리킬 메서드
static void SayHello(string name)
{
Console.WriteLine($"안녕하세요, {name}님!");
}
static void Main()
{
// 델리게이트 인스턴스 생성 및 초기화
GreetDelegate greet = SayHello;
// 델리게이트 호출
greet("홍길동"); // 출력: 안녕하세요, 홍길동님!
}
}
다중 메서드 호출 (Multicast Delegate)
델리게이트는 여러 메서드를 참조할 수 있습니다. 이를 멀티캐스트 델리게이트라고 합니다.
static void SayGoodMorning(string name)
{
Console.WriteLine($"좋은 아침입니다, {name}님!");
}
static void Main()
{
GreetDelegate greet = SayHello;
greet += SayGoodMorning; // 델리게이트 체인 추가
// 모든 메서드 호출
greet("홍길동");
// 출력:
// 안녕하세요, 홍길동님!
// 좋은 아침입니다, 홍길동님!
}
💡 멀티캐스트 델리게이트를 사용할 때, 마지막 메서드의 반환 값만 유지됩니다. 반환값이 중요한 경우 단일 델리게이트를 사용해야 합니다.
2. 익명 메서드와 람다 표현식
델리게이트를 초기화할 때 메서드 이름 대신 **익명 메서드(Anonymous Method)**나 **람다 표현식(Lambda Expression)**을 사용할 수 있습니다. 이를 통해 간단한 메서드를 델리게이트에 직접 정의할 수 있습니다.
익명 메서드
static void Main()
{
// 익명 메서드로 델리게이트 초기화
GreetDelegate greet = delegate (string name)
{
Console.WriteLine($"안녕하세요, {name}님! (익명 메서드 사용)");
};
greet("홍길동");
}
람다 표현식
람다 표현식은 익명 메서드를 간결하게 작성하는 방법입니다. => 연산자를 사용하여 입력 매개변수와 실행 블록을 구분합니다.
static void Main()
{
// 람다 표현식으로 델리게이트 초기화
GreetDelegate greet = (name) => Console.WriteLine($"안녕하세요, {name}님! (람다 표현식 사용)");
greet("홍길동");
}
💡 람다 표현식은 코드가 간결해지고 가독성이 좋아지는 장점이 있어 자주 사용됩니다.
3. 이벤트의 선언과 구독
**이벤트(Event)**는 델리게이트를 기반으로 구현되며, 객체 간의 상호작용을 처리하는 데 사용됩니다. 이벤트는 주로 GUI 애플리케이션이나 비동기 작업에서 상태 변경을 알리는 데 사용됩니다.
이벤트 선언
이벤트는 event 키워드를 사용하여 선언하며, 특정 델리게이트 타입을 기반으로 동작합니다.
using System;
// 델리게이트 선언
delegate void Notify(string message);
// 이벤트를 포함하는 클래스
class Publisher
{
// 이벤트 선언
public event Notify OnNotify;
public void Publish(string message)
{
// 이벤트가 구독된 경우 실행
if (OnNotify != null)
{
OnNotify(message);
}
}
}
class Subscriber
{
public void DisplayMessage(string message)
{
Console.WriteLine($"구독자가 받은 메시지: {message}");
}
}
class Program
{
static void Main()
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
// 이벤트 구독
publisher.OnNotify += subscriber.DisplayMessage;
// 이벤트 발생
publisher.Publish("새로운 소식이 있습니다!");
// 출력: 구독자가 받은 메시지: 새로운 소식이 있습니다!
}
}
이벤트 구독 해제
이벤트에서 구독을 해제하려면 -= 연산자를 사용합니다.
publisher.OnNotify -= subscriber.DisplayMessage; // 이벤트 구독 해제
기본 제공 이벤트 델리게이트: EventHandler와 EventHandler<T>
C#에서는 EventHandler와 EventHandler<T>라는 기본 제공 델리게이트를 사용하여 이벤트를 선언할 수 있습니다. 이는 표준화된 이벤트 패턴을 따르며, 추가 데이터를 전달할 수 있는 기능을 제공합니다.
using System;
class Publisher
{
// EventHandler<T>를 사용한 이벤트 선언
public event EventHandler<string> OnNotify;
public void Publish(string message)
{
OnNotify?.Invoke(this, message); // 이벤트 발생
}
}
class Subscriber
{
public void HandleEvent(object sender, string message)
{
Console.WriteLine($"구독자가 받은 메시지: {message}");
}
}
class Program
{
static void Main()
{
Publisher publisher = new Publisher();
Subscriber subscriber = new Subscriber();
// 이벤트 구독
publisher.OnNotify += subscriber.HandleEvent;
// 이벤트 발생
publisher.Publish("새로운 이벤트 발생!");
// 출력: 구독자가 받은 메시지: 새로운 이벤트 발생!
}
}
💡 EventHandler를 사용하면 이벤트 핸들러 메서드에서 sender와 추가 데이터를 받을 수 있어 더욱 유연한 이벤트 처리가 가능합니다.
다중 구독자 처리
하나의 이벤트에 여러 구독자를 추가하면 모든 구독자의 핸들러가 호출됩니다.
class Program
{
static void Main()
{
Publisher publisher = new Publisher();
// 여러 구독자 등록
publisher.OnNotify += (message) => Console.WriteLine($"구독자 1: {message}");
publisher.OnNotify += (message) => Console.WriteLine($"구독자 2: {message}");
publisher.Publish("다중 구독 테스트");
// 출력:
// 구독자 1: 다중 구독 테스트
// 구독자 2: 다중 구독 테스트
}
}
델리게이트는 메서드 참조를 관리하고, 이벤트는 델리게이트를 기반으로 객체 간의 상호작용을 처리하는 도구입니다. 익명 메서드와 람다 표현식은 델리게이트를 더 간결하고 유연하게 사용할 수 있도록 하며, 이벤트는 객체 간 통신을 더욱 안전하고 효과적으로 관리할 수 있습니다.