Category Archives: Unity3D

Unity C# – Delegate 알아보기

unity_logo

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

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

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

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

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

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

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

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

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

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

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

Unity C# – IDisposable 알아보기

unity_logo

이번에는 IDisposable 인터페이스에 대해서 알아보겠습니다. C#은 가비지콜랙터(Garbage Collector)를 가지고 있습니다. 이 GC는 기본적으로 관리되는 모든 객체들의 참조 링크를 관리하며 더이상 참조되지 않는 객체들을 자동으로 메모리에서 소거하는 작업을 수행합니다. 하지만 GC는 창 핸들, 열린 파일, 스트림과 같이 관리되지 않는 리소스들을 인식하지 못합니다.

다음은 문제가 발생할 가능성이 있는 StreamReader의 사용 예 입니다.

하지만 위의 코드는 ReadToEnd() 메소드를 수행하는 과정에서 오류가 발생할 가능성이 있습니다. 이때에 Close()가 호출되지 않고 반환될 가능성이 있습니다. 이러한 문제를 대응하기 위해 흔히들 try-catch-finally 구문을 사용해 볼 수 있습니다.

위의 코드는 ReadToEnd() 메소드를 수행중에 예외가 발생되면 발생한 예외의 내용을 로그에 출력하게 됩니다. 그리고 예외가 발생하거나 성공하거나 상관없이 Close() 메소드를 정상적으로 수행하게 됩니다. 하지만 이러한 복잡한 과정 없이 Close() 호출을 알아서 호출해주는 구문이 있습니다. 위와 같은 방법이 아닌 using 블록을 사용하여 다음과 같이 처리할 수 있습니다.

위의 코드에서 우선 눈에 띄는 것은 using 키워드를 사용했다는 점과 Close() 를 명시적으로 호출하지 않고 있다는 부분입니다. 이제 IDisposable에 대해 이야기를 해볼 때인 것 같습니다.

스크린샷 2016-08-11 오후 6.22.38

SteamReader는 TextReader의 자식 클래스입니다. 그리고 이 TextReader는 IDisposable 인터페이스를 구현하고 있습니다. 스크린샷 2016-08-11 오후 6.25.08

이 IDisposable 인터페이스는 Dispose() 메소드 하나만을 가지고 있네요. 이 IDisposable 인터페이스를 구현한 클래스는 Dispose() 클래스를 구현해야 하며 여기서 자신의 메모리 할당 내역을 정리해야 합니다. 위에서 보여준 예제에서 보여지는 StreamReader 역시 Dispose() 클래스를 구현하고 있으며 여기서 리소스를 정리하는 적절한 처리가 되어있을 것입니다.

이제 위의 코드는 IDisposable 인터페이스를 구현하고 있는 클래스를 인스턴스화 하여 사용하며 using 블록을 나가는순간 (심지어 오류가 발생하더라도) Dispose() 가 호출되어 사용한 리소스가 자동으로 정리됩니다.

그렇다면 using 블록 내부에서 발생한 예외는 어떻게 처리할 수 있을까요? 다음과 같은 방법으로 처리할 수 있습니다.

using 바깥쪽에 try-catch 문을 사용해도 using 블록을 빠져나갈 때 Dispose() 가 호출됩니다.

참고 : https://msdn.microsoft.com/ko-kr/library/system.idisposable(v=vs.110).aspx