C# 대리자(Delegate) 이해하기: 함수 참조와 이벤트 가이드
C# 대리자(delegate)는 C 또는 C++의 함수 포인터와 유사합니다. 대리자는 메서드에 대한 참조를 저장하는 참조 형식 변수이며, 이 참조는 런타임에 변경할 수 있습니다.
대리자 선언
대리자 선언은 대리자가 참조할 수 있는 메서드를 결정합니다. 대리자는 대리자와 동일한 시그니처를 가진 메서드를 참조할 수 있습니다.
예를 들어, 다음과 같은 대리자를 생각해 보세요.
public delegate int MyDelegate(string s);
앞의 대리자는 단일 string 매개 변수를 받고 int 형식 변수를 반환하는 모든 메서드를 참조하는 데 사용할 수 있습니다.
대리자 선언 구문은 다음과 같습니다.
delegate <반환 형식> <대리자 이름> <매개 변수 목록>
대리자 인스턴스화
대리자 형식이 선언되면 new 키워드를 사용하여 대리자 객체를 생성하고 특정 메서드와 연결해야 합니다. 대리자를 생성할 때 new 식에 전달되는 인수는 메서드 호출과 유사하게 작성되지만 메서드에 대한 인수는 없습니다. 예를 들어:
public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
다음 예제는 정수 매개 변수를 받고 정수 값을 반환하는 메서드를 참조하는 데 사용할 수 있는 대리자의 선언, 인스턴스화 및 사용을 보여줍니다.
Live Demo
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl {
class TestDelegate {
static int num = 10;
public static int AddNum(int p) {
num += p;
return num;
}
public static int MultNum(int q) {
num *= q;
return num;
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
// 대리자 인스턴스 생성
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
// 대리자 객체를 사용하여 메서드 호출
nc1(25);
Console.WriteLine("Value of Num: {0}", getNum());
nc2(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
위 코드를 컴파일하고 실행하면 다음과 같은 결과가 생성됩니다.
Value of Num: 35
Value of Num: 175
대리자 다중 전송(Multicasting)
대리자 객체는 "+" 연산자를 사용하여 구성할 수 있습니다. 구성된 대리자는 구성된 두 대리자를 호출합니다. 동일한 형식의 대리자만 구성할 수 있습니다. "-" 연산자를 사용하여 구성된 대리자에서 구성 요소 대리자를 제거할 수 있습니다.
이 대리자 속성을 사용하여 대리자가 호출될 때 호출될 메서드의 호출 목록을 만들 수 있습니다. 이를 대리자의 다중 전송(multicasting)이라고 합니다. 다음 프로그램은 대리자의 다중 전송을 보여줍니다.
Live Demo
using System;
delegate int NumberChanger(int n);
namespace DelegateAppl {
class TestDelegate {
static int num = 10;
public static int AddNum(int p) {
num += p;
return num;
}
public static int MultNum(int q) {
num *= q;
return num;
}
public static int getNum() {
return num;
}
static void Main(string[] args) {
// 대리자 인스턴스 생성
NumberChanger nc;
NumberChanger nc1 = new NumberChanger(AddNum);
NumberChanger nc2 = new NumberChanger(MultNum);
nc = nc1;
nc += nc2;
// 다중 전송 호출
nc(5);
Console.WriteLine("Value of Num: {0}", getNum());
Console.ReadKey();
}
}
}
위 코드를 컴파일하고 실행하면 다음과 같은 결과가 생성됩니다.
Value of Num: 75
대리자 사용
다음 예제는 대리자의 사용을 보여줍니다. printString 대리자는 문자열을 입력으로 받고 아무것도 반환하지 않는 메서드를 참조하는 데 사용할 수 있습니다.
이 대리자를 사용하여 두 메서드를 호출합니다. 첫 번째는 문자열을 콘솔에 출력하고, 두 번째는 파일에 출력합니다.
Live Demo
using System;
using System.IO;
namespace DelegateAppl {
class PrintString {
static FileStream fs;
static StreamWriter sw;
// 대리자 선언
public delegate void printString(string s);
// 이 메서드는 콘솔에 출력
public static void WriteToScreen(string str) {
Console.WriteLine("The String is: {0}", str);
}
// 이 메서드는 파일에 출력
public static void WriteToFile(string s) {
fs = new FileStream("c:\\message.txt", FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
sw.WriteLine(s);
sw.Flush();
sw.Close();
fs.Close();
}
// 이 메서드는 매개 변수로 대리자를 받아 필요에 따라 메서드를 호출
public static void sendString(printString ps) {
ps("Hello World");
}
static void Main(string[] args) {
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);
sendString(ps1);
sendString(ps2);
Console.ReadKey();
}
}
}
위 코드를 컴파일하고 실행하면 다음과 같은 결과가 생성됩니다.
The String is: Hello World