| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
- PS
- System Programming
- Online Judge
- Network Programming
- Data Structure
- Toy Project
- C++
- BOJ
- c#
- git
- 독서
- Unity
- multi-thread
- Today
- Total
I'm FanJae.
[20260515] C# ( Event ) 본문
1. 정의
- event는 어떤 사건이 발생했을 때, 그 사실을 다른 객체에게 알려주는 기능이다.
- 예를 들어, 플레이어가 코인을 먹었을 때 다음 동작이 필요할 수 있다.
플레이어가 코인을 먹음
-> UI 갱신
-> 효과음 재생
-> 이펙트 출력
- 이때 Player가 UI, SFX, VFX를 직접 호출하지 않고, 코인을 먹었다는 사실만 이벤트로 알리는 구조를 만들 수 있다.
2. 필요한 이유
- 이벤트를 사용하지 않으면 Player 가 다른 객체들을 직접 알고 있어야 한다.
public class Player
{
private UI ui;
private SFX sfx;
private VFX vfx;
public void GetCoin()
{
ui.UpdateUI();
sfx.CoinSound();
vfx.CoinEffect();
}
}
- Player가 UI, 사운드, 이펙트까지 직접 신경써야 하며 Player의 역할이 많아지게 된다.
- 이에 따라서, 새 기능이 추가될 때 Player 코드도 수정해야 한다.
- 이때 이벤트를 사용하면 Player는 코인을 먹었다는 사실만 알리면 된다.
OnCoinCollected?.Invoke(coin);
- 사실을 알리면 이벤트에 등록된 메서드들이 알아서 실행된다.
3. 적용하지 않을 때 발생하는 문제
- 이벤트를 사용하지 않으면 객체 간 결합도가 높아진다.
- 예를 들어, 코인을 획득 했다고 할 때 업적 시스템을 추가한다면, Player 코드에 추가해야 한다.
achievement.CheckCoinAchievement();
- 기능이 추가될수록 Player 클래스가 계속 커진다.
- Player가 코인 획득만 담당하는 것이 아닌, UI 갱신, 효과음, 이펙트, 업적, 퀘스트 모두 호출하게 되는 것이다.
- 이벤트를 사용하면 Player는 그대로 두고, 외부에서 새 기능을 구독시키면 된다.
player.OnCoinCollected += achievement.CheckCoinAchievement;
4. 올바른 적용법 예시
using System;
internal class Program
{
public class Player
{
private int coin;
// 코인을 획득했을 때 발생하는 이벤트
// int 값은 현재 코인 개수를 의미한다.
public event Action<int> OnCoinCollected;
public void GetCoin()
{
coin++;
Console.WriteLine("플레이어가 코인을 얻음");
// 이벤트 발생
// 등록된 메서드가 있다면 현재 coin 값을 전달하면서 실행한다.
OnCoinCollected?.Invoke(coin);
}
}
public class UI
{
public void UpdateUI(int coin)
{
Console.WriteLine($"UI 코인 수 갱신 : {coin}");
}
}
public class SFX
{
public void CoinSound(int coin)
{
Console.WriteLine($"{coin}번째 코인 효과음 재생");
}
}
public class VFX
{
public void CoinEffect(int coin)
{
Console.WriteLine($"{coin}번째 코인 획득. 반짝 효과!");
}
}
static void Main()
{
Player player = new Player();
UI ui = new UI();
SFX sfx = new SFX();
VFX vfx = new VFX();
// 이벤트 구독
// 플레이어가 코인을 얻으면 UI 갱신 메서드 실행
player.OnCoinCollected += ui.UpdateUI;
// 플레이어가 코인을 얻으면 효과음 메서드 실행
player.OnCoinCollected += sfx.CoinSound;
player.GetCoin();
Console.WriteLine();
// 나중에 이펙트 기능 추가
player.OnCoinCollected += vfx.CoinEffect;
player.GetCoin();
Console.WriteLine();
// 효과음 기능 제거
player.OnCoinCollected -= sfx.CoinSound;
player.GetCoin();
}
}
player.OnCoinCollected += ui.UpdateUI;
player.OnCoinCollected += sfx.CoinSound;
- 위 코드는 OnCoinCollected 이벤트에 메서드를 등록하는 것이다.
OnCoinCollected?.Invoke(coin);
- 이 코드에 의해 이벤트에 등록된 메서드들이 실행된다.
5. Delegate와 Event의 차이 (★)
- 핵심은 직접 대입 및 호출 가능 여부에 있다.
- 일반적으로 델리게이트는 외부에서 직접 대입하거나 호출이 가능하다.
public Action OnDelegate;
sender.OnDelegate = listener1.ReAction;
sender.OnDelegate = listener2.ReAction;
sender.OnDelegate = listener3.ReAction;
- 이렇게 = 대입을 사용하면 기존에 등록된 메서드가 덮어 씌워진다.
- 반면 이벤트는 외부에서 +=, -= 만 할 수 있다. (즉, 외부에서 대입 못한다.)
public event Action OnEvent;
sender.OnEvent += listener1.ReAction;
sender.OnEvent += listener2.ReAction;
- 위와 같은 +=, -= 연산은 가능하다.
sender.OnEvent = listener3.ReAction; // 불가능
sender.OnEvent?.Invoke(); // 불가능
- 하지만 이와 같은 작업은 불가능하며, 이벤트는 기본적으로 선언한 클래스 내부에서만 발생이 가능하다.
※ 즉, 일반 델리게이트는 외부에서 직접 대입 및 호출이 가능하다.
※ 하지만, 이벤트는 외부에서 대입할 수 없고, 직접 호출도 불가능하다. event는 오직 외부에서 구독과 구독 해지만 가능하며, 선언된 클래스 내부에서만 발생 시킬 수 있다.
6. 장점
- 객체 간 결합도를 낮출 수 있다.
- 특정 사건이 발생했을 때 여러 객체에게 알릴 수 있다.
- +=, -= 기능을 통해 쉽게 추가하거나 제거 가능하다.
- 이벤트를 발생시키는 객체는 누가 반응하는지 몰라도 된다.
- 일반 델리게이트보다 안전하다. (외부에서 대입, 호출이 불가능하기 때문에)
- 옵저버 패턴 구조를 만들때 사용 가능하다.
7. 단점 / 주의점
① 구독 해제를 하지 않으면 문제가 생길 수 있다.
- 이벤트에 등록한 객체가 더 이상 필요 없어졌는데도 구독이 남아 있으면, 의도치 않게 메서드가 계속 호출될 수 있다.
player.OnCoinCollected -= ui.UpdateUI;
- 따라서, 필요 없어졌다면 구독 해제를 해야한다.
② 실행 순서에 과하게 의존하면 좋지 않다.
- 이벤트에 여러 메서드를 등록하면 등록된 순서로 실행된다.
- 이벤트 구조는 기본적으로 ‘알림’에 가깝다. 특정 실행 순서에 강하게 의존하는 로직은 피하는 것이 좋다.
③ 이벤트 내부에서 예외가 발생하면 이후 메서드 실행에 영향을 줄 수 있다.
- 이벤트에 여러 메서드가 연결되어 있는 경우, 앞에서 실행된 메서드가 예외를 발생시키면 뒤에서 등록된 메서드가 실행되지 않을 수 있다.
- 따라서 중요한 이벤트 처리에서는 예외 처리도 고려가 필요하다.
③ 이벤트 내부에서 예외가 발생하면 이후 메서드 실행에 영향을 줄 수 있다.
- 이벤트에 여러 메서드가 연결되어 있을 때, 앞에서 실행된 메서드가 예외를 발생시키면 뒤에 등록된 메서드가 실행되지 않을 수 있다.
- 따라서 중요한 이벤트 처리에서는 예외 처리도 고려해야 한다.
④ 이벤트를 너무 많이 사용하면 흐름 추적이 어려워진다.
- 이벤트는 호출하는 쪽과 실행되는 쪽이 분리된다.
- 이것 때문에 결합도는 낮아지지만, 반대로 코드만 보고 어떤 메서드가 실행되는지 추적하기가 어려워질 수 있다.
8. 정리
- 이벤트는 어떤 사건이 발생했다는 사실을 외부에 알리는 기능이다.
- 이벤트는 대리자를 기반으로 동작한다.
- 외부 객체는 이벤트에 메서드를 등록하거나 제거할 수 있다.
- 이벤트는 선언한 클래스 내부에서만 발생시킬 수 있다.
- 일반 델리게이트보다 안전하게 알림 구조를 만들 수 있다.
- UI 갱신, 사운드 재생, 이펙트 출력, 퀘스트 갱신과 같은 구조에 적합하다.
※ 즉, Event는 특정 사건이 발생했을 때, 그 사건에 관심이 있는 객체들이 반응할 수 있도록 알려주는 델리게이트 기반 알림 기능이다.
'Unity > Unity 초격차캠프' 카테고리의 다른 글
| [20260518] Git 용어 정리 (0) | 2026.05.18 |
|---|---|
| [20260518] C# ( Exception ) (0) | 2026.05.18 |
| [20260515] C# ( Func ) (0) | 2026.05.15 |
| [20260515] C# ( Action ) (0) | 2026.05.15 |
| [20260515] C# ( Delegate, 대리자 ) (0) | 2026.05.15 |