I'm FanJae.

[20260515] C# ( Event ) 본문

Unity/Unity 초격차캠프

[20260515] C# ( Event )

FanJae 2026. 5. 15. 21:54
 

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
Comments