C#에서 delegate와 event는 이벤트 기반 프로그래밍에서 중요한 역할을 합니다.
이번 포스팅에선 delegate와 event에 대해 알아봅시다
Delegate
delegate는 메서드에 대한 참조를 보관하는 타입입니다.
다시 말해, delegate는 하나 이상의 메서드를 가리킬 수 있는 변수와 같습니다.
delegate를 사용하면 메서드를 다른 메서드의 매개변수로 전달하거나, 메서드를 변수에 할당하는 등의 작업을 할 수 있습니다.
이를 통해 코드의 유연성을 높이고, 이벤트 핸들러나 콜백 메서드 같은 기능을 구현할 때 유용하게 사용됩니다.
아래는 기본적인 delegate 코드 예시이다.
public delegate void MyDelegate(string message);
public class Example
{
public void MyMethod(string message)
{
Console.WriteLine(message);
}
public void Execute()
{
MyDelegate del = new MyDelegate(MyMethod);
del("Hello, Delegate!");
}
}
Delegate 변수 초기화
Delegate 변수를 초기화하는 가장 기본적인 방법은 다음과 같다.
여기서 'MyDelegate'는 delegate 타입이며, 'MyMethod'는 이 delegate 타입에 맞는 메서드이다.
MyDelegate del = new MyDelegate(MyMethod);
// C# 2.0 이상에서는 delegate 인스턴스를 생성할 때 'new' 키워드를 생략할 수 있으며,
// 다음과 같이 더 간결하게 작성할 수 있다.
MyDelegate del = MyMethod;
Delegate에 메서드 추가, 삭제하기
Delegate에 변수에 메서드를 추가하고 싶을 때는 '+=' 연산자를 사용할 수 있습니다. 이렇게 하면 여러 메서드를 delegate의 invocation list에 추가할 수 있으며, delegate가 호출될 때 list에 있는 모든 메서드가 순서대로 실행됩니다.
제거하고 싶을 때는 '-=' 연산자를 사용하면 해당 메서드가 invocation list에서 제거됩니다.
del += AnothorMethod; // 추가하기
del -= AnothorMethod; // 제거하기
위 내용을 담은 예시 코드입니다.
public delegate void MyDelegate(string message);
public void MyMethod(string message)
{
Debug.log($"MyMethod : {message}");
}
public void AnotherMethod(string message)
{
Debug.log($"AnotherMethod : {message}");
}
// Delegate 초기화 및 사용
MyDelegate del = MyMethod;
// Delegate에 또 다른 메서드 추가
del += AnotherMethod;
// Delegate 호출
del("Hello, World!");
// 출력 결과
// MyMethod : Hello, World!
// AnotherMethod : Hello, World!
ChatGPT
Q :
delegate 변수의 매개 변수가 string message인데, delegate 변수에 등록할 메서드 역시 같은 매개변수 형식을 가져야 하는 거야?
네, 맞습니다. delegate에 등록할 메서드는 delegate가 정의한 매개변수의 형식과 반환 타입이 일치해야 합니다. 이는 delegate의 계약이라고 볼 수 있는데, 이를 통해 delegate를 사용하는 코드가 일관된 방식으로 메서드를 호출할 수 있게 해 줍니다.
예를 들어, delegate가 다음과 같이 정의되었다면:
public delegate void MyDelegate(string message);
이 delegate 타입의 변수에 등록할 수 있는 메서드는 매개변수로 string 타입의 message를 받고, 반환 타입이 void인 메서드여야 합니다.
즉, delegate에 등록하려는 메서드의 시그니처(signature, 즉 메서드의 반환 타입과 매개변수의 타입 및 순서)가 delegate 정의와 일치해야 합니다.
올바른 메서드 예시:
public void CorrectMethod(string message)
{
Console.WriteLine(message);
}
올바르지 않은 메서드 예시(메서드의 반환 타입과 매개변수 타입이 일치하지 않음):
public int IncorrectMethod(int number) // 이 메서드는 MyDelegate에 맞지 않음
{
Console.WriteLine(number);
return 13;
}
delegate에 메서드를 등록할 때는 이러한 규칙을 따라야 하며, 이를 통해 delegate를 호출하는 코드는 어떤 메서드가 실행될지 명확하게 알 수 있고, 타입 안전성을 보장받을 수 있습니다.
Event
우선 시작하기에 앞서, Unity 개발을 하다보니 헷갈리는 개념이 있었다.
Event Listener, Event Handler, Event, AddListener, Invoke, 등등...
코드의 이해를 돕기 위해 변수 이름을 변경했습니다.
using System;
// 1. Delegate 정의 : 이벤트 핸들러가 가질 메서드의 시그니처를 정의합니다.
public delegate void MyEventHandler(string message);
public class Publisher
{
// 2. Event 선언 : delegate를 기반으로 하는 이벤트를 선언합니다.
public event MyEventHandler MyEvent;
// 이벤트 발생시키는 메서드
public void RaiseEvent()
{
// 5. Invoke : 이벤트에 등록된 메서드(이벤트 핸들러)를 호출합니다.
// 이벤트가 null 이 아닐 경우에만 호출하여 NullReferenceException 방지
MyEvent?.Invoke("Hello from Publisher");
}
}
public class Subscriber
{
// 이벤트 핸들러 : 이벤트가 발생했을 때 실행할 메서드를 정의합니다.
public void OnMyEvent(string message)
{
Console.WriteLine($"Event received with message : {message}");
}
}
class Program
{
static void Main(string[] args)
{
Publisher publisher = new Publisher();
Subscriber subscriber = new subscriber();
// 3. Event 구독 : 이벤트에 이벤트 핸들러(리스너 메서드)를 등록합니다.
publisher.MyEvent += subscriber.OnMyEvent;
// 이벤트 발생
publisher.RaiseEvent();
// 4. Event 구독 해제 : 이벤트에서 이벤트 핸들러를 제거합니다.
publisher.MyEvent -= subscriber.OnMyEvent;
}
}
조금 더 변수와 이벤트 핸들러(메서드)의 이름을 명확하게 구분해봅시다.
- Delegate 타입 이름: Delegate 타입의 이름은 이 delegate의 용도나 사용될 컨텍스트를 반영할 수 있도록 명명하는 것이 좋습니다. 예를 들어, 문자열 메시지를 처리하는 이벤트의 경우, delegate 타입 이름을 MessageEventHandler로 할 수 있습니다.
public delegate void MessageEventHandler(string message);
- 이벤트 이름: 이벤트의 이름은 이벤트가 나타내는 동작이나 발생 상황을 기반으로 명명합니다. 예를 들어, 메시지를 처리하는 이벤트라면 MessageReceived라고 할 수 있습니다.
public event MessageEventHandler MessageReceived;
- 이벤트 핸들러 메서드 이름: 이벤트 핸들러 메서드의 이름은 해당 메서드가 어떤 이벤트에 반응하여 어떤 작업을 수행하는지를 반영할 수 있도록 명명합니다. 예를 들어, 메시지 수신 이벤트에 대한 핸들러라면 HandleMessageReceived라고 할 수 있습니다.
public void HandleMessageReceived(string message)
{
Console.WriteLine($"Received message: {message}");
}
ChatGPT
Q :
등록된 메서드는 이벤트 핸들러이고 이때의 메서드를 이벤트에 구독하는 과정에서 subscriber 객체 자체가 이벤트 리스너로 동작하는 거야
A :
맞습니다. 정리하자면, 이벤트 시스템에서의 "구독(subscribe)" 과정에서 메서드는 이벤트 핸들러 역할을 하고, 해당 메서드를 이벤트에 등록하는 객체(여기서는 Subscriber 객체)는 이벤트 리스너 역할을 합니다.
이벤트 핸들러는 실제 이벤트가 발생했을 때 수행될 로직을 포함하는 메서드입니다.
이벤트 리스너는 이벤트의 발생을 "듣고" 있으며, 이벤트 발생 시 등록된 이벤트 핸들러를 호출합니다.
이 과정에서 Subscriber 객체는 자신의 메서드(OnMyEvent 메서드)를 특정 이벤트(MyEvent 이벤트)에 등록하여, 이벤트가 발생할 때 해당 메서드가 호출되도록 합니다.
따라서, Subscriber 객체는 이벤트 리스너의 역할을 수행하며, OnMyEvent 메서드는 등록된 이벤트 핸들러의 역할을 수행합니다.
'Language > C#' 카테고리의 다른 글
| 프로그래머스 원소들의 곱과 합 (1) | 2024.05.01 |
|---|---|
| 간결한 코드 작성 : Auto-Implemented Properties(자동으로 구현되는 속성), implict property(암묵적 속성) - 2 (0) | 2024.03.11 |
| 간결한 코드 작성 : Auto-Implemented Properties(자동으로 구현되는 속성), implict property(암묵적 속성) - 1 (1) | 2024.03.10 |