Unity) Delegate(델리게이트) , Event(이벤트)

강성현
∙∙조회 11

1. Delegate(델리게이트)

메서드 자체를 인자로 넘겨주는 형식 입니다. (함수 x)

csharp
public delegate void ScoreChangedHandler(int score);

 private void Start()  
{  
    _scoreChanged = PrintScore;  
    _scoreChanged.Invoke(10);  
}

하지만, 델리게이트를 직접 선언하는 경우보다는
뒤에 나올 ==Action==과 ==Func== 을 사용을 하는 경우가 많다.

 

1-1) Invoke

델리게이트 객체가 참조하고 있는 실제 메서드를 안전하고 명시적으로 실행시키는 명령어 입니다.

  • Invoke가 없어도 실행이 가능하지만, delegate와 일반 함수를 구분할 수 있어 가독성이 높아집니다.
    del(10,20) 과 del.Invoke(10,20) 는 내부적으로 완전히 같습니다.

 

 


1-2) 델리게이트 체인

여러 함수들을 델리게이트 함수에 할당해놓고 순서대로 호출하는 형식입니다.

==+=로 더하고-=== 로 뺍니다.

csharp
private ScoreChangedHandler _scoreChanged;

// 담기  
_scoreChanged += PrintScore;  
_scoreChanged += SaveScore;

// 떼기  
_scoreChanged -= SaveScore;
  • 비어 있는 delegate를 부르면 NullReferenceException 이 발생하기 때문에
    ==if 형식의 조건문==이나 null조건부 연산자인 ==scoreChanged?.Invoke(_score);== 로 null 체크를 해주는 것이 좋습니다.

 

상황무슨 일이 일어나나
담은 적 없는 메서드를 -=로 뺀다아무 일도 일어나지 않는다. 오류가 나지 않는다
같은 메서드를 +=로 두 번 더한다두 번 담기고 부를 때 두 번 불린다
두 번 담긴 것을 -=로 한 번 뺀다하나만 빠진다. 뒤쪽에 담긴 것부터 빠진다

 


1-3) Action, Func

매개변수의 반환형의 조합마다 ==delegate== 줄을 새로 쓰는 일은 번거롭기 때문에 자주 쓰는 조합이 이미 만들어져있습니다.

System 네임스페이스에 있어, ==using System;== 이 필요합니다.

이름반환값
Action없다
Func있다

 

  • ==Action== 은 반환값이 없는 메서드를 담습니다.
형태담을 수 있는 메서드
Action매개변수가 없고 반환값이 없는 것
Action<int>int 하나를 받고 반환값이 없는 것
Action<int, string>int와 string을 받고 반환값이 없는 것
csharp
private Action<int> _scoreChanged;
private void Start()  
{  
    _scoreChanged += PrintScore;  
    _scoreChanged.Invoke(10);  
}

 

  • ==Func== 은 반환값이 있는 메서드를 담습니다.
형태담을 수 있는 메서드
Func<int>매개변수가 없고 int를 돌려주는 것
Func<int, bool>int 하나를 받고 bool을 돌려주는 것
Func<int, string, bool>int와 string을 받고 bool을 돌려주는 것

※ 반환값이 있는 델리게이트에 여럿을 담으면 마지막 것의 값만 남습니다.
여럿이 나눠 받는 알림에는 ==Func== 을 쓰진 않기 때문에 게임코드에서 압도적으로 쓰는 것은 ==Action== 입니다.

 


2. Event (이벤트)

public 으로 델리게이트를 열어놓게 되면 외부에서 쉽게 변경이 가능해 문제가 발생할 수 있습니다.

필드 앞에 ==event== 를 붙여 외부에서 할 수 있는 일들을 줄여 리스너를 더하고 빼는 것만 됩니다.

밖에서 하는 일event 없을 때event 있을 때
+=로 더하기된다된다
-=로 빼기된다된다
=로 대입하기된다막힌다
Invoke로 부르기된다막힌다

 

2-1) 구독과 해제

구독과 해제는 ==OnEnable== , ==OnDisalbe== 에서 합니다.

오브젝트가 켜져 있는 동안에만 알람을 받습니다.

  • 이벤트 이름은 ==OnScoreChanged== 처럼 On 을 붙인 PascalCase 로 보통 사용합니다.

==ScoreManager.Instance.OnScoreChanged += OnScoreChanged;==

왼쪽은 상대가 가진 이벤트 이고, 오른쪽은 내 클래스의 메서드 입니다.

 

직접 부르는 형태

이벤트 형태

알릴 곳이 하나 늘 때

ScoreManager를 고친다

새로 만든 쪽에서 걸기만 한다

점수 매니저가 아는 것

받는 쪽의 클래스 이름과 메서드 이름

아무것도 모른다

받는 쪽이 아는 것

아무것도 모른다

점수 매니저와 그 이벤트 이름

붙이는 자리

한 오브젝트에 함께 있어야 한다

어디에 있어도 된다

csharp
using System;  
using UnityEngine;

public class ScoreManager : MonoBehaviour  
{  
    private int _score;

    public static ScoreManager Instance { get; private set; }

    public event Action<int> OnScoreChanged;

    private void Awake()  
    {  
        SetSingleton();  
    }

    public void AddScore(int amount)  
    {  
        _score += amount;

        if (OnScoreChanged != null)  
        {  
            OnScoreChanged.Invoke(_score);  
        }  
    }

    private void SetSingleton()  
    {  
        Instance = this;  
    }  
}