[C#] Delegate(대리자) 정리(1)
댓글 0
댓글을 작성하려면 로그인이 필요합니다.
아직 댓글이 없습니다. 첫 번째 댓글을 작성해보세요!
Delegate는 메서드를 변수처럼 다룰 수 있는 타입이라는 설명을 듣고 C언어의 함수 포인터가 떠올랐다. 당시엔 작성된 코드를 가져다 쓰는 정도라 깊게 이해하지 못했는데, C#에서는 이벤트, Linq 등 다양한 곳에서 자주 등장해 이번 기회에 제대로 정리해보려 한다.
1편에서는 Delegate의 개념과 기본 사용법을, 2편에서는 Action, Func 등 자주 쓰이는 내장 Delegate 정리와 실습 코드를 연습해보고자 한다.
C#에서 Delegate(대리자) 는 메서드를 변수처럼 저장하고 전달할 수 있는 타입이다.
두 메서드가 구조가 동일하고 변환 로직만 다를 때, 새로운 변환 방식이 필요할 때마다 메서드를 추가해야한다.
안좋은 예)
// Delegate 없이 - 변환 방식마다 메서드를 따로 만들어야 함
static int Double(int x) => x * 2;
static int Square(int x) => x * x;
static int Negate(int x) => -x;
static void PrintConverted_Double(int[] numbers)
{
foreach (var n in numbers)
Console.WriteLine(Double(n));
}
static void PrintConverted_Square(int[] numbers)
{
foreach (var n in numbers)
Console.WriteLine(Square(n));
}
변환 방식마다 메서드를 따로 만들어야함 -> Negate를 구하고 싶으면 PrintConverted_Negate를 만들어야함
좋은 예)
// Delegate 사용 - 변환 로직만 바꿔서 하나의 메서드로 해결
delegate int Converter(int x);
static void PrintConverted(int[] numbers, Converter convert)
{
foreach (var n in numbers)
Console.WriteLine(convert(n));
}
// 사용
int[] nums = { 1, 2, 3, 4, 5 };
PrintConverted(nums, x => x * 2); // Double
PrintConverted(nums, x => x * x); // Square
PrintConverted(nums, x => -x); // Negate
변환 로직 함수를 매개변수로 받아서 하나의 메서드로 원하는 Converter를 구할 수 있다
다른 예로는 아래와 같은 것들이 있다.
// Delegate 인스턴스 생성
SayDelegate say = Hi;
say();
💡 팁: Delegate는 클래스와 같은 레벨(네임스페이스 내부)이나 클래스 내부에 선언할 수 있음
// 방법 1: 메서드 이름만 사용 (간결한 방식)
SayDelegate say = Hi;
// 방법 2: new 키워드 사용 (명시적 방식)
SayDelegate say2 = new SayDelegate(Hi);
// Delegate 선언: void 매개변수와 void형 반환하는 Delegate
delegate void SayDelegate();
// 참조할 메서드
static void Hi() => Console.WriteLine("안녕하세요.");
SayDelegate sayPointer = new SayDelegate(Hello);
// 방법 1: 대리자 변수에 괄호를 붙여 호출
sayPointer();
// 방법 2: Invoke() 메서드를 명시적으로 호출
sayPointer.Invoke();
delegate void SayDelegate();
static void Hello() => Console.WriteLine("Hello Delegate");
// 대리자 인스턴스 생성
GetAreaDelegate pointer = GetArea;
// 호출
Console.WriteLine(pointer.Invoke(10));
Console.WriteLine(pointer(10));
// int를 받아 double을 반환하는 대리자
delegate double GetAreaDelegate(int r);
// 원의 넓이를 계산하는 메서드
static double GetArea(int r) => 3.14 * r * r;
추가) Delegate는 정적 메서드와 인스턴스 메서드 모두 참조할 수 있다
하나의 Delegate에 여러 메서드를 연결할 수 있다
// 대리자에 메서드 추가
CarDriver go = GoForward;
go += GoLeft;
go += GoRight;
// 한 번의 호출로 모든 메서드 실행
go();
Console.WriteLine();
// 메서드 제거
go -= GoLeft;
go();
delegate void CarDriver();
static void GoForward() => Console.WriteLine("직진");
static void GoLeft() => Console.WriteLine("좌회전");
static void GoRight() => Console.WriteLine("우회전");
+= 연산자로 메서드를 추가하고 -= 연산자로 메서드를 제거한다.
특징
// 다른 동작을 전달
RunnerCall(Go);
Console.WriteLine();
RunnerCall(Back);
delegate void Runner();
static void Go() => Console.WriteLine("직진");
static void Back() => Console.WriteLine("후진");
// 대리자를 매개변수로 받는 메서드
static void RunnerCall(Runner runner)
{
Console.WriteLine("=== 실행 시작 ===");
runner();
Console.WriteLine("=== 실행 종료 ===");
}
별도의 메서드를 정의하지 않고 대리자에 직접 코드를 할당할 수 있다.
// delegate 키워드로 익명 메서드 정의
SayDelegate say = delegate()
{
Console.WriteLine("반갑습니다.");
};
say();
delegate void SayDelegate();