# delegate의 필요성
C#의 delegate는 C++의 함수포인터와 같은 개념이다
아래를 통해 왜 필요한지 알아보자
예를 들어서 버튼이 눌리는 경우, 특정 작업을 구현하고 싶다고 가정하자
그렇다면 ButtonPressed 같은 함수 내부에 원하는 작업을 작성하면 된다
static void ButtonPressed()
{
// 기존 코드
// 어쩌고 저쩌고 기능 추가
}
그러나 위의 코드는 복잡성을 증가시키고
또한, 사실상 게임 엔진에서는 저런 함수 자체만을 제공하는 것이고
함수 내부를 수정하지는 못하도록 해두었다
그래서 아래와 같이
사실상 ButtonPressed의 함수의 인자로
우리가 원하는 함수자체를 인자로 넘겨주고 싶은 것이 핵심이다
static void ButtonPressed(// 함수를 인자로 넘겨주고 싶다...)
{
// 인자로 받은 함수 실행
}
이처럼 함수A에서 인자로 함수 B를 넘겨주고
함수 A에서 함수 B를 역으로 호출하는 이러한 과정을
콜백방식이라고 한다
즉, 함수A는 자신이 직접 함수 B를 호출하는 것이 아니라,
외부에서 함수B를 인자로 전달받아
그 인자를 내부에서 역호출하는 것을 콜백 방식이라는 것이다
여기서 함수A는 인자(함수 B)가 정확히 어떤 함수인지 미리 알 수 없다
그저 '어떤 함수든 나에게 넘겨주면 내가 정해진 시점에 호출해 줄게'라는 의미이다
delegate는 위의 예시뿐 아니라
매우 다양하게 활용된다
# delegate 사용법
public delegate void MyPrinter(string message); // 델리게이트 구현
public class Printer
{
public void Print(MyPrinter myprinterFunction) // 델리게이트를 인자로 활용
{
// 다른 로직들이 있을 수 있음
myprinterFunction($"Console: Hello"); // 콜백 호출
}
public void Message(string message)
{
Console.WriteLine($"Console: {message}");
}
}
public class Program
{
public static void Main(string[] args)
{
Printer printer = new Printer();
printer.Print(printer.Message); // 이렇게 인자로 넘겨줄 수 있다
}
}
# delegate 객체 활용법
delegate를 인자로 받는 함수에서
바로 함수를 넣는 방식도 있지만
함수 객체를 생성하고 넣어주는 방식이 추천된다
그 이유는 좀더 직관적이고
체이닝 기능(+=, -=) 및 다양한 기능 활용이 가능하기 때문이다
public delegate void MyPrinter(string message);
public class Printer
{
public void Print(MyPrinter myprinterFunction) // 프린트 기능
{
// 다른 로직들이 있을 수 있음
myprinterFunction($"Console: Hello"); // 콜백 호출
}
public void Message(string message)
{
Console.WriteLine($"Console: {message}");
}
public void Error(string message)
{
Console.WriteLine($"Console: Error with {message}");
}
}
public class Program
{
public static void Main(string[] args)
{
// 1번 방식
Printer printer = new Printer();
printer.Print(printer.Message); // 그냥 직접 전달
// 2번 방식 (추천)
MyPrinter temp = new MyPrinter(printer.Message); // 델리게이트 객체 생성
printer.Print(temp); // 객체로 전달
temp += printer.Error; // 체이닝
}
}
# delegate 체이닝
+= 연산자를 통해 체이닝을 하는 경우에
함수를 여러개 체이닝을 한다는 의미이고
인자들을 모두 저장하는 것은 아니다
그렇기에 아래의 체이닝 코드들이 각각 어떤 출력 결과를 지니는지 확인할 필요가 있다
public delegate void MyPrinter(string message);
public class Printer
{
public void PrintToConsole(string msg)
{
Console.WriteLine($"Console: {msg}");
}
public void PrintToLog(string msg)
{
Console.WriteLine($"Log: {msg}");
}
public void PrintToError(string msg)
{
Console.WriteLine($"Error: {msg}");
}
}
public class Program
{
public static void Main(string[] args)
{
Printer printer = new Printer();
MyPrinter myDelegate = printer.PrintToConsole;
myDelegate += printer.PrintToLog;
myDelegate += printer.PrintToError;
myDelegate("Triple message");
// 출력 결과
// Console: Triple message
// Log: Triple message
// Error: Triple message
}
}
public delegate void MyPrinter(string message);
public class Printer
{
public void PrintToConsole(string msg)
{
Console.WriteLine($"Console: {msg}");
}
public void PrintToLog(string msg)
{
Console.WriteLine($"Log: {msg}");
}
public void PrintToError(string msg)
{
Console.WriteLine($"Error: {msg}");
}
}
public class Program
{
public static void Main(string[] args)
{
Printer printer = new Printer();
MyPrinter myDelegate = printer.PrintToConsole;
myDelegate("Initial message");
myDelegate += printer.PrintToLog;
myDelegate("Chained message");
myDelegate += printer.PrintToError;
myDelegate("Triple message");
// 출력 결과
// Console: Initial message
// Console: Chained message
// Log: Chained message
// Console: Triple message
// Log: Triple message
// Error: Triple message
}
}
각기 다른 인자를 전달하고 싶다면,
단순히 아래와 같이 체이닝이 아닌 각 메서드를 개별적으로 호출하거나,
람다함수를 사용하여 각 메서드 호출과 인자를 캡슐화한 후 별도로 실행하는 등
다른 다양한 방법을 통해 작성하면 된다
MyPrinter myDelegate1 = printer.PrintToConsole;
myDelegate1("Initial message");
MyPrinter myDelegate2 = printer.PrintToLog;
myDelegate2("Chained message");
MyPrinter myDelegate3 = printer.PrintToError;
myDelegate3("Triple message");
# Generic과 활용도 가능
using System;
public delegate T Operation<T>(T a, T b);
class Program
{
static int Add(int a, int b)
{
return a + b;
}
static double Multiply(double a, double b)
{
return a * b;
}
static void Main() {
Operation<int> addOperation = Add;
Operation<double> multiplyOperation = Multiply;
Console.WriteLine($"덧셈 결과: {addOperation(5, 3)}");
Console.WriteLine($"곱셈 결과: {multiplyOperation(2.5, 4.0)}");
}
}
'C# > [루키스] 실전 문법' 카테고리의 다른 글
[C# 섹션 8] Exception (2) | 2025.06.26 |
---|---|
[C# 섹션 8] Lambda (0) | 2025.06.25 |
[C# 섹션 8] Event (0) | 2025.06.25 |
[C# 섹션 8] Property (0) | 2025.06.24 |
[C# 섹션 8] Interface (0) | 2025.06.24 |