Unity C# – Delegate 알아보기

unity_logo

이번에는 delegate 에 대해서 알아보겠습니다. C#에서는 이 delegate 를 사용하여 함수에 대한 참조를 나타내는 방법입니다. delegate를 인스턴스화 하면 호환되는 파라미터 타입/개수와 반환 타입이 같은 모든 메소드를 참조할 수 있게 됩니다. 한번 참조된 delegate 를 통해 참조된 함수를 대리로 호출하는 것이 가능해집니다. C++의 함수 포인터와 동일한 형태로 사용가능하지만 안전하게 캡슐화 하여 사용할 수 있다는 장점이 있습니다.

public delegate void Del(string message);

위의 코드는 string 타입 파라미터를 하나 가지고 있고 반환 타입이 없는(void) delegate Del 을 선언하는 코드입니다. 이 delegate는 인스턴스화 하고 나면 참조하고 있는 실제 메소드를 대리로 호출하는것이 가능해지며 마치 기존의 메소드를 직접 호출하는것처럼 호출할 수 있습니다.

public delegate void Del(string message);

void Start () {
	Del handler = new Del(DelegateMethod);
	handler ("Hello Delegate");
}

void DelegateMethod(string message) {
	Debug.Log (message);
}

위의 코드를 보면 Del delegate를 인스턴스화 하며 DelegateMethod를 참조하도록 하고 있는 것을 볼 수 있습니다. new 키워드를 사용하지 않고 좀 더 간단하게 선언하는 방법도 있습니다.

//Del handler = new Del(DelegateMethod);
Del handler = DelegateMethod;

이러한 delegate를 사용하여 특정 작업이 수행된 뒤에 호출되는 콜백(Callback) 으로 사용할 수 있습니다.

public delegate void Del(string message);

void Start () {
	Del handler = DelegateMethod;
	RunHeavyJob (handler);
}

void RunHeavyJob(Del handler) {
	// 오래 걸리는 작업 수행
	string result = ...;

	handler(result);
}

void DelegateMethod(string message) {
	Debug.Log ("Result: " + message);
}

위의 코드는 특정 작업이 호출된 뒤에 결과를 출력하는데 사용할 DelegateMethod 메소드를 delegate를 통해서 RunHeavyJob에 넘겨 콜백으로 사용하는것을 볼 수 있는 예제입니다.

여기까지는 수많은 언어에서 볼 수 있는 일반적인 형태의 콜백, 리스너, 함수 포인터와 같은 기능이지 않을까 생각합니다. 하지만 추가로 멋진 기능이라고 생각되는 멀티캐스트(Multicast) 호출 기능을 사용할 수 있습니다.

public delegate void Del(string message);

void Start () {
	Del handler = DelegateMethod1;
	handler += DelegateMethod2;
	handler += DelegateMethod3;

	handler ("Hello Delegate");
}

void DelegateMethod1(string message) {
	Debug.Log ("#1 " + message);
}

void DelegateMethod2(string message) {
	Debug.Log ("#2 " + message);
}

void DelegateMethod3(string message) {
	Debug.Log ("#3 " + message);
}

위의 코드는 한번 인스턴스화 한 delegate 인 handler 변수에 계속해서 새로운 delegate를 추가하는 과정입니다. 그리고 handler를 호출하게 되면 지금까지 등록된 delegate 모두를 대리호출 하게 됩니다. 이때에는 등록된 순서대로 차례차례 호출이 되게 됩니다. 즉 결과는 다음과 같이 출력됩니다.

#1 Hello Delegate
#2 Hello Delegate
#3 Hello Delegate

물론 다음과 같은 방법으로 등록된 delegate를 제거하는것도 가능합니다.

handler -= DelegateMethod2;

위의 코드를 수행하면 이미 등록되어있던 DelegateMethod1, DelegateMethod2, DelegateMethod3 중에 DelegateMethod2가 제거되게 됩니다.

이미 등록된 delegate의 수를 확인하려면 다음과 같이 하면 됩니다.

int invocationCount = handler.GetInvocationList ().GetLength (0);

참고 :
https://msdn.microsoft.com/ko-kr/library/ms173171.aspx
https://msdn.microsoft.com/ko-kr/library/ms173172.aspx