delegate는 메서드를 값처럼 전달하기 위해서 사용한다.
이를 통해 메서드를 변수처럼 저장하고, 매개변수로 전달하거나, 다른 메서드로부터 반환받을 수 있다.
대리자 사용 방법
- 대리자 선언 : 대리자 타입을 선언하고, 대리자가 참조할 메서드의 반환 타입과 매개변수를 정의한다.
- 대리자 인스턴스화 : 선언된 대리자 타입을 사용하여 대리자 인스턴스를 생성한다.(여기서 대리자가 참조할 메서드를 지정한다.)
- 대리자 호출 : 대리자 인스턴스를 통해 메서드를 호출
대리자는 .NET 고급 프로그래밍의 핵심을 이루며, 콜백 메커니즘 구현, 이벤트 처리, 비동기 프로그래밍 등 다양한 영역에서 광범위하게 활용된다.
콜백 메커니즘 구현
콜백 메커니즘은 프로그램에서 어떤 작업이 완료된 후 특정 동작을 실행할 수 있게 하는 편리한 방법이다.
그리고 대리자를 사용하는 콜백 메커니즘 구현은 프로그래밍에서 매우 강력한 패턴 중 하나이다.
대리자를 통해 메서드를 다른 메서드의 매개변수로 전달할 수 있게 되며, 이를 통해 실행 될 콜백을 유연하게 지정할 수 있게 해준다.
<대리자 사용 전 코드>
namespace ConsoleApp1
{
public interface ICallback
{
void OnComplete();
}
public class CallbackHandler : ICallback
{
public void OnComplete()
{
Console.WriteLine("콜백 메서드 호출");
}
}
public class WithoutDelegate
{
public void ProcessTask(ICallback callback)
{
Console.WriteLine("Task is being processed");
callback.OnComplete();
}
}
public class Program
{
static void Main(string[] args)
{
WithoutDelegate wd = new WithoutDelegate();
ICallback callback = new CallbackHandler();
wd.ProcessTask(callback);
}
}
}
<대리자를 사용한 콜백 메커니즘>
namespace ConsoleApp1
{
public delegate void Callback();
public class WithDelegate
{
public void ProcessTask(Callback callback) //대리자를 매개변수로 받는 메서드
{
Console.WriteLine("Task is being processed");
//콜백 메서드 실행
callback?.Invoke(); //?.는 null이면 호출X null이 아니면 호출
}
}
public class Program
{
public static void MyCallback() //콜백 메서드
{
Console.WriteLine("Task completed. Now running the callback.");
}
static void Main(string[] args)
{
WithDelegate wd = new WithDelegate();
//Callback callback = () => Console.WriteLine("Task completed. Now running the callback.");
Callback callback = new Callback(MyCallback);
wd.ProcessTask(callback);
}
}
}
이벤트 처리
이벤트 처리란 어떤 일이 발생했을 때 미리 등록해 둔 코드가 자동으로 실행되도록 하는 구조이다.
이벤트 처리를 구현할때도 대리자를 사용하면 이벤트를 훨씬 간단하게 정의하고 관리할 수 있다.
<인터페이스 기반 이벤트 처리>
namespace ConsoleApp1
{
public interface IEventHandler
{
void HandleEvent();
}
public class EventHandler1 : IEventHandler
{
public void HandleEvent()
{
Console.WriteLine("EventHadler1 called");
}
}
public class EventHandler2 : IEventHandler
{
public void HandleEvent()
{
Console.WriteLine("EventHadler2 called");
}
}
public class WithoutDelegate
{
private List<IEventHandler> subscribers = new List<IEventHandler>();
public void Subscribe(IEventHandler handler)
{
subscribers.Add(handler);
}
public void Unsubscribe(IEventHandler handler)
{
subscribers.Remove(handler);
}
public void TriggerEvent()
{
foreach (var handler in subscribers)
{
handler.HandleEvent();
}
}
public class Program
{
static void Main(string[] args)
{
var publisher = new WithoutDelegate();
var handler1 = new EventHandler1();
var handler2 = new EventHandler2();
publisher.Subscribe(handler1);
publisher.Subscribe(handler2);
publisher.TriggerEvent();
publisher.Unsubscribe(handler1);
publisher.TriggerEvent();
}
}
}
}
<대리자 기반의 이벤트 처리>
namespace ConsoleApp1
{
public class WithDelegate
{
public event Action MyEvent;
public void TriggerEvent()
{
MyEvent?.Invoke();
}
}
public class Program
{
static void Main(string[] args)
{
WithDelegate wd = new WithDelegate();
// 이벤트 핸들러, Action에 람다식(익명 메서드)을 대입
Action handler1 = () => Console.WriteLine("Event1 triggered!");
Action handler2 = () => Console.WriteLine("Event2 triggered!");
// 이벤트 구독
wd.MyEvent += handler1;
wd.MyEvent += handler2;
// 이벤트 발생
wd.TriggerEvent();
// 이벤트 구독 해제
wd.MyEvent -= handler2;
// 이벤트 발생
wd.TriggerEvent();
}
}
}
대리자를 사용하지 않으면, 모든 구독자는 동일한 메서드 시그니처를 구현해야 하고, 이벤트 관리를 위해 추가적인 코드가 필요하지만, 대리자를 이용하면 이벤트 구독과 발행 과정이 더 유연하고 간결해지고 다양한 시그니처의 메서드를 쉽게 처리할 수 있다.
<사용 예제>
public class Program
{
// 대리자 선언
public delegate void MyDelegate(string message);
// 대리자가 참조할 메서드
public static void DisplayMessage(string message)
{
Console.WriteLine(message);
}
static void Main(string[] args)
{
// 대리자 인스턴스화
MyDelegate del = new MyDelegate(DisplayMessage);
// 대리자 호출
del("안녕하세요~~");
}
}
using Project1;
using System;
using System.Diagnostics;
class Program
{
delegate int Calc(int a, int b);
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
void Execute(Calc calc)
{
Console.WriteLine(calc(10, 5));
}
static void Main(string[] args)
{
Program p = new Program();
Calc add = new Calc(p.Add);
Calc sub = new Calc(p.Sub);
p.Execute(add);
p.Execute(sub);
}
}
public class Mathematics
{
delegate int CalcDelegate(int x, int y);
static int Add(int x, int y) { return x + y; }
static int Sub(int x, int y) { return x - y; }
static int Multiply(int x, int y) { return x * y; }
static int Divide(int x, int y) { return x / y; }
CalcDelegate[] methods;
public Mathematics()
{
methods = new CalcDelegate[] { Add, Sub, Multiply, Divide };
}
public void Calculate(char opCode, int operand1, int operand2)
{
switch (opCode)
{
case '+':
Console.WriteLine(methods[0](operand1,operand2));
break;
case '-':
Console.WriteLine(methods[1](operand1, operand2));
break;
case '*':
Console.WriteLine(methods[2](operand1, operand2));
break;
case '/':
Console.WriteLine(methods[3](operand1, operand2));
break;
}
}
class Program
{
delegate void WorkDelegate(char arg1, int arg2, int arg3);
public static void Main()
{
Mathematics math = new Mathematics();
WorkDelegate work = math.Calculate;
work('+', 10, 5);
}
}
}
'C#' 카테고리의 다른 글
| [C#] LINQ(데이터 쿼리) (0) | 2026.02.19 |
|---|---|
| 스레딩 (0) | 2026.01.13 |
| BCL (0) | 2026.01.10 |
| [C#] Collection / Generic Collection (0) | 2026.01.04 |