삽질의 현장/- .NET

#052_닷넷(.NET)_.Net Framework 기본 - 대리자(delegate)

shovelman 2015. 11. 3. 19:55


안녕하세요 삽잡이입니다.


이번 시간에는 대리자에 대해서 알아보려고합니다.


대리자는 우선 다섯가지 형식중 하나의 형식입니다.

똑같은 클래스 형식이지만 중요하니 떼어뒀지요.


이 대리자의 목적은 

'내가 원하는 메서드를 가리키고, 이 객체로 호출을 하는 것이 목적입니다.'

즉, 내가 원하는 메서드가 있다면 그 메서드를 가리키고,

그 메서드를 delegate로 호출하는 것이 목적이지요.

좀 더 정확하게 말하자면 '메서드 처럼 동작하는 객체'를 만들어내는 것이 delegate 의 목적입니다.


이와 비슷한 개념으로는 C의 함수 포인터 ,C++의 Functor가 있습니다.


C, C++, C#에 이런 기능들이 있는 것은

'함수 처럼 동작하는 어떤 것'을 만들어보자는 것이며, 

이 어떤 것이 객체지향에서는 '객체'라고 부르는 것이지요...

즉, '함수처럼 동작하는 객체'가 있다면 유용하다는 사실을 알았기에 만들어낸 것입니다.


왜 이런 기능이 필요할까요?

여러가지 이유가 있겠지만, 그 중 핵심은 CallBack입니다.



Server가 Client의 로직, 메서드, 함수를 호출하고 사용하는 경우를

'Callback'이라고 부르는 것입니다.

대부분 Server는 OS, Platform, Library가 되지요...


아무튼... C#의 delegate는 callback을 특화해놓은 기능임을 알았습니다.

그런데, delegate는 callback에서만 사용되는 기능이 아닙니다.

callback에만 특화되도록 만든 기능은 이벤트입니다.

이 이벤트는 callback이 목적인데, 상대측에서 호출하는 것을 의미하지요.


콜백이란, '어떤 신호가, 어떤 이벤트가 발생하면 알려줄래?'라는 의미입니다.

Client 측에서 무엇인가 Server에게 요청을 했을 때,

Server에서 언제 완료되는지를 모르는 Client를 위해 

완료가 되거나, 필요한 일이 있을 경우 알려달라고 하는 기능입니다.


그래서 GUI의 핵심은 이벤트입니다.

API를 배우신 분들은 아시겠지만, 메시지라고도 부르지요.


이 이벤트는 delegate 없이 존재할 수가 없습니다.

delegate 에서도 콜백의 기능만을 목적으로 만들어진 전혀 다른 문법인 이벤트...

즉, delegate를 등에 엎고 Callback만을 위해 만들어진 문법이 C#, .Net의 이벤트라는 것입니다.


대리자(delegate)는 메서드의 주소, 넘길 인자, 반환 값을 필요로 합니다.

이 정보를 대리자가 갖고 있는다 이겁니다.

대리자를 반드는 방법은 

기존 메서드의 시그니처에서 delegate 키워드를 붙이기만 하면 됩니다.



메서드의 시그니처가 아닌,

대리자 또는 대리자 클래스가 되는 것입니다.

이 대리자로 부터 만들어진 객체를 대리자 또는 대리자 객체라고 부르지요.


delegate라는 것은 클래스, 인스턴스 이 둘을 표현할 수 있습니다.

정확하게는 delegate 클래스, delegate 객체로 만들어지는 것이고,

이를 통틀어서 delegate라고도 부른다 이겁니다.



delegate 객체를 만들기 위해서는 이처럼 작성합니다.

이처럼 객체를 생성하고, sd를 통해 해당 메서드를 그대로 호출할 수있게 됩니다.

즉, 대리자이지만, 메서드처럼 동작하는 객체이기 때문에 사용이 가능해진것입니다.


delegate에는 '동기', '비동기' delegate가 있습니다.


동기 딜리게이트는 'InVoke()' 메서드를 통해 호출이 됩니다.

비동기 딜리게이트는 'BeginInvoke()', 'EndInvoke()' 메서드를 통해 호출이 되지요.


비동기 딜리게이트는 함수를 호출하고 완료될 때까지 기다리는 것에 대해 보장하지 않습니다.

즉, 호출하고 내 할일 한다 이겁니다.

사실, 비동기 호출을 할 때에는 내부적으로 쓰레드를 띄워줍니다.

그래서 BeginInvoke()를 통해 시작하고, EndInvoke()를 통해 마무리를 하는 것이지요.


아무튼 이처럼 두가지 호출방식을 통해 딜리게이트가 수행되는 것입니다.



이와 같이 함수를 가리키고 함수처럼 동작하는 객체인 

대리자를 사용해 함수 호출을 할 수 있습니다.



사실 요즘은 굳이 객체 생성하지 않더라도 

자동적으로 함수 객체를 생성해서 보관할 수 있게 해줍니다.

즉, new 연산자를 안써도 된다 이겁니다.


또한, 딜리게이트를 '멀티캐스트'를 사용하여 '+=', '-=' 연산을 통해

한 방에 출력을 할 수 있습니다. 

단, 참조가 같다면 이라는 전재가 붙습니다.



다시 한번 말씀드리지만, delegate는 여러 곳에서도 사용이 가능하지만,

callback에 맞춰서 사용하는 방법만 보여드렸을 뿐입니다.


이 대리자에는 공변성(Convariance)이라는 기능에 입각하여 

자동으로 변환될 수 있는 기능을 제공합니다.


여기서 공변성이란, return 타입이 부모 형식의 타입이라면 변환 가능한 타입,

반공변성이란 매개변수 타입이 부모형식 타입 

(즉, 계층구조 타입)이라면 변환가능한 타입으로 만들어줍니다.

이를 통해 유연성이 높아지지요...


즉, 공변성은 delegate가 부모 타입형식을 반환하도록 만들면 

모든 자식 타입을 똑같이 취급하는 것입니다.

그리고 반공변성의 경우에는 return 타입이 아닌 매개변수만 가능하지요


또한, delegate에서도 제네릭을 제공해줍니다.



해당 add 메서드는 int형만을 취급합니다.


그런데, 



이와 같이 제네릭 형식을 사용한다면,

int형식 외에 다른 형식또한 가능해집니다.

즉, T를 내가 결정할 수 있게 되었다 이겁니다.



이번 시간은 여기까지 하도록 하겠습니다.


이상 삽잡이였습니다!



<참고 : C# and the .NET4 Platform>