뭐라도 쓰겠지
25.03.24 / 델리게이트(Delegate) 본문
델리게이트란, 말 그대로 대리자라는 의미를 가지며 특정 메소드(함수)를 참조할 수 있는 타입(Type)이다. 간단히 말해, 델리게이트는 C/C++의 함수 포인터와 유사한 역할을 수행하지만, C#에서는 타입으로 안전하게 관리되는 방식으로 제공된다. 델리게이트를 사용하면 메소드를 변수처럼 전달하거나, 실행 시점을 유연하게 조절하는 등 다양한 구조를 구현할 수 있다.
- 1. 델리게이트의 특징
- 1-1. 형식 안전(type-safe)
- C# 델리게이트는 메소드의 시그니처(반환 타입 및 매개변수 목록)와 동일해야만 한다. 이 때문에 컴파일 시점에 오류를 방지할 수 있다.
- 1-2. 멀티캐스트(Multicast) 지원
- 하나의 델리게이트 인스턴스에 여러 메소드를 등록할 수 있다. 이렇게 여러 메소드를 등록해 두면 델리게이트를 호출할 때 연결된 모든 메소드가 순차적으로 호출된다.
- 1-3. 객체 지향적인 처리
- 델리게이트는 클래스 내무 멤버처럼 취급된다. 클래스나 구조체에서 인스턴스 멤버로 선언하거나, static으로 선언하는 것도 가능하며, 접근 제한자도 지정할 수 있다.
- 1-4. 이벤트(event)와 긴밀한 연관성
- C#에서 이벤트 기능은 델리게이트를 기반으로 작동한다. 이벤트는 '어떤 일이 발생했을 때, 연결된 델리게이트들을 호출한다'라는 메커니즘을 제공하며, 델리게이트가 이런 이벤트 구독/발생 구조에서 핵심 역할을 수행한다.
- 1-1. 형식 안전(type-safe)
- 2. 기본 사용 예시
using System;
public delegate int Calculate(int x, int y);
// 반환 타입: int, 매개변수: (int x, int y)
class Program
{
static void Main(string[] args)
{
// 델리게이트 인스턴스 생성, Add 메서드를 참조
Calculate calc = Add;
// 메서드 호출
int result1 = calc(3, 4);
Console.WriteLine($"Add(3,4) = {result1}"); // 출력: Add(3,4) = 7
// 델리게이트가 참조하는 메서드를 Subtract로 변경
calc = Subtract;
int result2 = calc(10, 5);
Console.WriteLine($"Subtract(10,5) = {result2}"); // 출력: Subtract(10,5) = 5
// 멀티캐스트 예시
calc += Add; // 여기서 calc에는 Subtract와 Add가 모두 등록
// calc(10, 5)를 호출하면 Subtract -> Add 순으로 호출
// 이때 마지막에 호출된 메서드(Add)의 반환값이 최종 결과로 들어옴
int result3 = calc(10, 5);
Console.WriteLine($"Multicast result = {result3}");
}
static int Add(int x, int y)
{
Console.WriteLine("Add 메서드 호출");
return x + y;
}
static int Subtract(int x, int y)
{
Console.WriteLine("Subtract 메서드 호출");
return x - y;
}
}
Add(3,4) = 7
Subtract(10,5) = 5
Subtract 메서드 호출
Add 메서드 호출
Multicast result = 15
위 예시에서 calc += Add; 구문을 통해 델리게이트 인스턴스에 두 번째 메소드를 추가로 등록할 수 있다. 멀티캐스트에서는 가장 마지막에 호출된 메소드의 반환값이 최종값으로 들어온다는 점을 주의 깊게 봐야 한다.
- 3. 델리게이트의 활용
- 3-1. 콜백(Callback) 메커니즘
- 긴 작업을 수행하는 함수에서, 특정 시점에 호출해 줄 메소드를 인자로 넘기고 싶을 때 델리게이트를 사용한다. 예를 들어, 파일 다운로드 라이브러리에서 '다운로드 진행 상황'을 업데이트할 함수(진행률 표시 메소드)를 델리게이트로 전달받아, 다운로드 루프 안에서 적절히 콜백하는 식이다.
- 3-2. 이벤트(Event) 처리
- Windows Form, WPF, Unity, ASP.NET 등 C# 기반 GUI/프레임워크에서는 대부분 이벤트로 동작한다. 이벤트를 구독하기 위해 델리게이트(핸들러)를 등록하고, 이벤트가 발생하면 등록된 델리게이트(핸들러)들이 자동으로 실행되는 식이다.
- 3-3. LINQ와 람다(Lambda)식
- C#에서 람다 식((x, y) => x + y)을 사용하는 것은 델리게이트의 간편화된 표현이다. 예를들어 Func<int, int, int> 같은 제네릭 델리게이트를 이용하여 LINQ 쿼리나 컬렉션 메소드(Where, Select, OrderbBy)에 람다 식을 넘길 때, 내부적으로 델리게이트를 사용하고 있다.
- 3-1. 콜백(Callback) 메커니즘
- 4. 제네릭 델리게이트
- C#에서는 자주 쓰이는 델리게이트 패턴을 위해 제네릭 델리게이트를 미리 정의해 두었다.
- 반환 값을 가지는 델리게이트 패턴
- Func<TResult>
- Func<t, TResult>
- Func<T1, T2, TResult>
- 반환 값이 없는 델리게이트 패턴(void 반환)
- Action<T>
- Action<T1, T2>
- 특정 조건을 확인하여 bool을 반환하는 델리게이트 패턴
- Predicate<T>
- 반환 값을 가지는 델리게이트 패턴
- 예를 들어, 다음 코드에서는 Func<int, int, int> 를 사용해 같은 계산 함수를 람다로 전달할 수 있다.
- C#에서는 자주 쓰이는 델리게이트 패턴을 위해 제네릭 델리게이트를 미리 정의해 두었다.
class Program
{
static void Main(string[] args)
{
Func<int, int, int> calc = (x, y) => x + y;
Console.WriteLine(calc(2, 3)); // 5
calc = (x, y) => x - y;
Console.WriteLine(calc(5, 2)); // 3
}
}
정리하자면 델리게이트는 C#에서 메소드를 가리키는 형식으로, 형식 안정성과 멀티캐스트 등을 지원한다. 콜백, 이벤트, 함수의 동적 할당, 람다 식 및 LINQ 표현식 등 광범위하게 활용된다. C#에서 제공하는 제네릭 델리게이트를 자주 사용하면 코드가 간결해지고 재사용성도 좋아진다. 이벤트는 델리게이트를 기반으로 이루어진 것으로, GUI나 게임, 서버 통신 등 이벤트 기반 프로그래밍에 광범위하게 쓰인다.
'프로그래밍 > C#' 카테고리의 다른 글
25.03.24 / 메모리 풀(Memory Pool) (0) | 2025.03.24 |
---|---|
25.03.24 / getter와 setter는 왜 쓰는걸까 (0) | 2025.03.24 |
25.03.24 / C# 배열 (0) | 2025.03.24 |
25.03.21 / 멤버 접근 지정자(Access Modifiers) (0) | 2025.03.21 |
25.03.21 / 클래스(Class)와 구조체(Struct)의 생성자(Constructor)와 소멸자(Destructor) (0) | 2025.03.21 |