728x90
C#에서 delegate(대리자)와 event(이벤트)는 둘 다 메서드를 가리키고 실행할 수 있는 기능을 제공하는 요소지만, 사용 목적과 방식에 차이가 있다.
delegate
- delegate는 특정 메서드의 참조를 저장하고 호출할 수 있는 타입이다. C++에서 함수 포인터와 비슷한 개념이라 생각하면 된다.
- 파라미터와 리턴 타입을 통해 정의하게 되며 이후 리턴, 파라미터 타입이 같은 메소드들과 호환되어 이 메소드들에 대한 참조를 가질 수 있게 된다.
- 사용 예시 : 콜백(callback) 메커니즘을 구현하거나, 특정 시점에 실행할 작업 목록을 정의할 때 유용하다.
콜백 메커니즘 : 특정 이벤트나 작업이 완료된 후 실행될 메서드를 미리 지정하는 방식
/// 매개변수가 없는 delegate
public delegate void Notify(); // delegate 선언
public class Process
{
public Notify? OnProcessComplete; // delegate 인스턴스 선언(null이 될 수 있도록 허용)
pbulic void StartProcess()
{
Console.WriteLine("Process Started.");
OnProcessComplete?.Invoke(); // OnProcessComplete가 null이 아니라면 참조한 메서드 호출
}
}
/// 매개변수와 return 타입이 있는 delegate
public delegate int Operation(int x, int y);
public class Calculator
{
// 메서드의 매개변수와 return 타입이 같음
public int Add(int x, int y)
{
return x + y;
}
public int Subtract(int x, int y)
{
return x - y;
}
}
public class Program()
{
public static void Main()
{
Calculator calculator = new Calculator();
Operation operation = Calculator.Add(); // delegate 선언 및 메서드 할당
Console.WriteLine("Add Result : " + operation(10, 5)); // 출력 : Add Result : 15
operation = Calculator.Subtract;
Console.WriteLine("Add Result : " + operation(10, 5)); // 출력 : Add Result : 5
}
}
/// deletage를 함수 인자로 넘겨서 호출하는 경우
using System;
public delegate void Notify(string message); // delegate 정의
public class Notifier
{
// 델리게이트를 인자로 받아서 호출하는 메서드
public void DoWork(Notify callback)
{
Console.WriteLine("Doing some work...");
// 델리게이트 호출
callback?.Invoke("Work completed!"); // null일 경우 안전하게 호출
}
}
public class Program
{
public static void Main()
{
Notifier notifier = new Notifier();
// 델리게이트에 할당할 메서드 정의
Notify notifyMethod = message => Console.WriteLine($"Callback message: {message}");
// DoWork 메서드에 델리게이트를 인자로 전달
notifier.DoWork(notifyMethod); // 출력: "Doing some work..." 및 "Callback message: Work completed!"
}
}
위의 예시와 같이 같은 타입의 매개변수를 받고 반환하는 delegate를 통해 함수의 참조를 넘겨서 원하는 타이밍에 호출을 하거나, delegate를 함수의 인자로 넘겨 콜백 패턴을 구현하는 등 다양한 곳에 사용할 수 있다.
event
- event도 델리게이트와 함께 사용되는, 특정 이벤트 발생 시 어떤 메서드가 실행될지 결정하는 메커니즘이다. 하지만, 가장 큰 차이점으로는 event를 호출할 수 있는 것은 해당 event를 가진 클래스만 가능하다는 것이다.
- 사용 예시 : Button.Click과 같은 UI 요소의 이벤트나 특정 조건에서 특정 기능을 호출하고 싶을 때 유용하다.
public class GameEvents
{
// 반환값이 없는 이벤트(매개변수 없음)
public event Action OnGameStart;
// 두 개의 int를 받아 int를 반환하는 이벤트
public event Func<int, int, int> OnCalculateScore;
// string을 받아 bool을 반환하는 이벤트
public event Predicate<string> OnCheckCondition;
public void StartGame()
{
Console.WriteLine("Game Starting...");
OnGameStart?.Invoke(); // OnGameStart가 null이 아닌 경우에 참조한 메서드 실행
}
public void CalculateScore(int a, int b)
{
int result = OnCalculateScore?.Invoke(a, b) ?? 0; // OnCalculateScore가 null이 아닌 경우에
// 참조한 메서드의 반환값을 저장
// null이라면 0을 저장
Console.WriteLine($"Calculated Score : {result}");
}
public void CheckCondition(string input)
{
bool isCondition = OnCheckCondition?.Invoke(input) ?? false;
Console.WriteLine(%"Condition Met : {isConditionMet}");
}
}
public class Program
{
public static void Main()
{
GameEvents gameEvents = new GameEvents();
// 람다식을 통해 이벤트 구독
gameEvents.OnGameStart += () => ConsoleWriteLine("Gmae has started!");
gameEvents.OnCalculateScore += (a, b) => a + b;
gameEvents.OnCheckCondition += input => input == "Win";
// 이벤트 실행
gameEvents.GameStart();
gameEvents.CalculateScore(5, 10);
gameEvents.CheckCondition("Win");
}
}
위와 같이 이벤트 구독과 호출을 이벤트가 정의된 클래스 내에서만 할 수 있다.
Action, Func, Predicate
이 키워드들은 자주 사용하게 되는 델리게이트를 템플릿화 한 것들이다. event 선언 시 해당 타입들을 사용할 수 있다.
- Action : 함수 파라미터가 T이고 반환값이 void인 경우 사용(최대 16개의 매개변수를 받을 수 있다.)
- Func<T, TResult> : 함수 파라미터가 T이고 반환 타입이 TResult인 경우 사용(최대 16개의 매개변수를 받을 수 있다.)
- Predicate : 함수 파라미터가 T이고 반환값이 bool인 경우 사용(매개변수 1개를 받을 수 있다.)
728x90
'언어(C, C++, C#)' 카테고리의 다른 글
[C#] 리플렉션(Reflection)과 속성(Attribute) (0) | 2024.11.14 |
---|---|
[C#] const vs readonly (0) | 2024.11.09 |
[C#] .NET, 컴파일 과정, CLS, CTS, CIL, CLI, CLR, JIT 컴파일 (1) | 2024.11.06 |
[C#] 접근 제한자(public, private, protected, internal 등) (0) | 2024.11.06 |
[C#] 깊은 복사 / 얕은 복사 (Deep Copy / Shallow Copy) (2) | 2024.11.06 |