Unity

C# 델리게이트(Delegate) in Unity

CCS_Cheese 2025. 1. 29. 18:50

오늘 시간에는 Delegate에 대해 알아보겠습니다.

먼저 Delegate가 무엇인지에 대해 이해해야 되는데요 아래와 같습니다.

 

Delegate란 번역해보면 대리자라는 의미입니다. Unity에서는 함수 포인터라는 개념으로도 많이 사용됩니다. 
메서드 자체를 인자로 넘겨주어 전달받은 곳에서 대리로 해당 메서드를 실행할 수 있습니다.

 

C#에서 delegate 기본형식은 아래와 같습니다

delegate 반환형 델리게이트명(인자);
delegate int Add(int parameter1, int parameter2);

delegate의 예제1
결과 값

이미지를 확인해 보면 delegate를 이용하여 Sum 함수를 호출한 것과, 단순호출한 것에 결과의 차이가 없음을 알 수 있습니다. 그렇다면 왜 delegate를 사용하는 것일까요? 

 

Delegate의 사용 이유

더보기

delegate는 위에서 설명했듯이 대리자로, 여러 메서드를 추가할 수있습니다. sum함수 뿐만아니라 시그니처가 동일한 메서드를 여러개 추가하여, 반복적인 메소드 호출, 코드 재사용성을 증가시킬 수 있습니다. 아래에서 자세히 알아보겠습니다.

 

시그니처란? 메소드 반환형식, 파라미터 형식을 의미하는데, 위에서 설명한 반환값, 파라미터의 형식이 동일하며, 메소드 이름이 다른 것을 시그니처가 같은 메서드라고 표현할 수 있습니다. 


다중 호출 Delegate 선언부
다중 호출 Delegate 예시

RPG 게임에서 몬스터를 Kill 했을 때 다양한 Event가 발생할 수 있습니다. 여기에서는 예시로, coin획득, exp획득, Score획득, 전체 몬스터감소로 예시를 들었습니다.

 

예시 1

  • 각 메서드 별로 필요한 파라미터만 전달받아서 각각 개별로 호출됨.
  • 몬스터를 Kill 했을 때의 처리 메서드가 늘어남에 따라 위와같은 모듈화 되어있는 메소드 호출이 증가함.

예시 2

  • MonsterKill delegate(대리자)에 각 시그니처가 동일하지만 처리되는 메서드가 다른 메소드를 참조(연결)
  • 스코어 획득, 코인 획득, 경험치 획득, 전체 몬스터수 감소 등의 메소드 파라미터의 형식이 동일해짐
  • 대리자(delegate) 하나의 호출로 한 번에 메서드들이 호출이 가능
  • 여기서 return value는 가장 마지막에 연결된 메서드의 리턴값이 전달되는 것으로 확인.
다양한 게임 장르에서 여러 이벤트동작에 있어 모듈화 되어있는 메서드들을 개별로 호출할 수 있지만, 처리되는 시점이 동일한 처리를 위와 같이 delegate를 활용하면 코드 재사용성, 유지보수 측면에서 이점을 얻을 수 있다고 생각합니다.

 

이제 이 delegate를 함수 포인터(파라미터)로 활용하는 것에 대해 알아보려고 합니다.

앞서 이야기했듯이 함수 포인터, 파라미터로 활용할 수 있는데 이를 예제 코드를 통해 알아보겠습니다.

 

MonsterSetup
Monster 생성 및 대미지 Trigger 설정

 

코드를 정리해 보면 다음과 같습니다.

  • Monster를 생성하는 Create에서, MonsterKill 처리에 대한 대리자(delegate)를 정의.
  • Create시에 정의 및 메서드 참조가 완료된 delegate를 Setup(파라미터)에 추가.
  • Monster내부에서 참조된 함수포인터만 Trigger 하여 몬스터 처치에 대한 Logic 처리 함수를 실행하여 의존성을 분리.

 

Delegate vs 람다식, 익명함수

Unity C# 프로그래밍을 하다 보면 위와 같은 용어가 종종 눈에 보입니다. 설명만 보았을 때는 비슷비슷한 거 같지만 하나하나 상세히 정리하는 것이 좋아 보여 해당 글에서 같이 정리하고자 합니다.

 

익명함수(Anonymous function)

  • 말 그대로 익명의 함수 : 함수명이 없는 함수를 의미합니다.
  • 해당 익명함수는 재사용이 불가능 : 다른 class에서 정의된 익명함수를 일반적인 방법으론 호출할 수없습니다.
  • 재사용하기 위해서는 delegate를 활용하여 익명함수를 참조하는 방식으로 처리가 가능합니다.

람다식(Lambda expressions)

  • 람다 선언 연산자 (=>)를 이용하여 익명함수를 만들 수 있습니다.
(input-parameters) => expression : expressions을 body로 하는 람다식
(input-parameters) => { <sequence-of-statements> } : 여러 State를 포함한 block을 body로 하는 람다식
  • 위 두 가지의 형태로 표현이 가능합니다.
  • input parameters가 1개일 때는 () 기호는 선택 사항입니다.

Delegate에 익명함수를 같이 사용한 예제

익명 함수 재사용 예제

  • AnonymousFunction Class에서 익명함수를 정의하고, 이를 delegate를 활용하여 함수를 참조합니다.
  • 해당 delegate를 직접 호출하여 return값을 출력할 수 있습니다.
  • 다른 Class에서 정의한 익명함수를 호출하기 위해 생성자를 통해 delegate를 파라미터로 전달하여 invoke 할 수 있습니다.

결과값

정리


정리하자면 delegate는, 익명함수, 실제 정의된 함수 두 가지를 참조할 수 있고, 시그니처만 동일하면 여러 메서드를 대리로 실행할 수 있습니다.
익명 함수를 만들기 위해서는 람다(Lambda)를 활용할 수 있고, 익명 함수는 일반적인 방법으로 재사용이 불가합니다. Why? 말 그대로 호출할 수 있는 이름이 없기 때문입니다.
익명 함수를 재사용하기 위해서는 delegate를 활용하여 익명 함수를 참조하고, delegate를 호출하는 방식으로 익명함수를 재호출(재사용) 합니다. 

 

위 예제 코드를 작성하면서 느낀 점


더보기

최초 설계 시에 각 이벤트마다 설정되는 Logic이 완벽하지 않을 때 추가적인 내부 로직이 추가될 때 예를 들어, 몬스터 처치 시에 퀘스트 정보가 업데이트된다거나 등의 처리를 모듈화 하여 추가하려면, 기본 로직에 추가하는 것이 아닌, 마찬가지로 모듈화 하여 delegate형태로 참초만 추가하여, 기능을 분리하면 유지보수 측면에서 좋을 것 같다고 느끼게 되었다. 

 

'Unity' 카테고리의 다른 글

Addressable Asset (6) - Download Progress 처리  (0) 2025.02.16
Unity Addressable Asset (5)  (0) 2025.02.13
Unity Runtime Memory 관리 - 1  (5) 2025.01.12
Unity Localization (2)  (4) 2025.01.04
Unity Addressable Asset (4)  (2) 2025.01.02