ITEM 17 :: EFFECTIVE C#
안녕하세요, 17번째 시간입니다. 알면 알수록 깊어만가는 C#…(먼산)
이번 챕터는 표준 Dispose 패턴을 구현하라, 입니다. 사실, 이렇게만 들어서는 잘 모를 수가 있는데요, 일단은 Dispose하면 생각나는 것이 있을 겁니다. 제 여러 글들을 봐왔다면 말이죠. 바로 IDisposable Interface 입니다. 이는, 적시에 Dispose를 호출하여, GC를 호출하고, 그로인해서 효과적인 메모리 관리를 하기 위한 인터페이스 입니다.
사실, 이 인터페이스는 구현해놓기만하면 꾸준히 사용할 수 있는 인터페이스이기도 하고, 이 인터페이스를 이용하여 많은 C# 개발자들이 이미 표준이라고 불릴만한 Dispose 패턴을 만들어놓기도 했습니다. 저희는 그 패턴대로 코드를 짜기만 하면 되는데, 그 패턴에 대해서 설명해주는 챕터입니다. C# 초급 개발자인 저로써는 상당히 기묘하고 어려운 내용이지만, 힘내서 달려보겠습니다. 가시죠.
설명
- 닷넷 프레임워크는 비 메모리 자원을 제거하기 위해 표준화된 패턴을 사용하고 있다! 그 패턴이란 아래와 같다.
- IDisposable Interface를 구현하여 비 관리 자원을 해제
- Dispose() 메서드의 호출을 잊었을 경우를 대비한 Finalizer 구현
- 하위 클래스에서 새로운 Dispose() 메서드를 정의할 경우를 대비한 protected virtual helper 메서드 구현
-
그러면 순서대로 IDisposable InterFace의 구현부터 설명하겠다.
-
비관리 자원(::내부 자원이 아닌 외부 자원의 경우)을 가지고 있는 클래스들이 상속관계에 있다면 최상위 클래스는 반드시 IDisposable Interface와 방어적인 코딩을 위한 Finalizer를 구현해야 한다. 이 때 IDisposable Interface는 하나의 메서드 만을 포함하고 있다. 바로 Dispose() 다.
-
따라서, IDisposable.Dispose()를 구현할 때에는 반드시 다음의 4가지 작업을 수행해야 한다.
- 비관리 자원의 해제
- 관리 자원의 해제
- 객체가 Dispose 되었음을 표시할 수 있는 상태 플래그 값 설정(이는 중복 호출을 막기위한 처리용 값임)
- Finalization 동작이 수행되지 못하도록 함
-
-
다음으로 Protected Virtual Helper 메서드다.
- 이 메서드가 필요한 이유는 일목요연하다. 하위 클래스에서 자신만의 Finalizer나 Dispose()를 구현할 경우, 상위 클래스의 자원을 해제할 수 없는 경우가 발생할 수 있기 때문이다. 또한 IDisposable.Dispose() 메서드와 Finalizer 는 비슷한 구현을 가지고 있다. 때문에 별도의 Protected virtual helper 메서드가 필요하다. - 예를들자면 플래그 값에 따라, // isDisposing == true : 관리, 비관리 자원 모두 해제, false : 비관리 자원만 해제, 같은 식으로 말이다. - 이 메서드는 IDisposable.Dispose()와 Finalizer 에서 호출되며, 하위 클래스에서는 이를 적절하게 오버라이딩하여 사용할 수 있다.
정리
즉, 위에서 설명한 대로의 패턴을 구축하게되면 적시에 비관리 자원과 관리 자원의 해제를 할 수 있고, 메모리 관리 효율이 증가하게 되며, 사전에 문제가 일어날 일을 방지할 수 있게 된다. 그러니 한번쯤은 구현을 해봐야 하는데, 필자가 구현하기엔 아직 비관리 자원을 사용해보지 않아서 잘 모르겠다. 아마, 다음에 비관리 자원을 사용할 때에는 이러한 패턴대로 구현을 해봐야 할 것 같다.