C# IDisposable

Featured image

Git Source


Finalizer를 선언하여 객체의 자원을 정리할 경우, 가비지 컬렉터의 메커니즘에 의해 객체의 제거 및 자원의 정리가 비결정적이라는 점을 해결하기 위해 제시된 방법이 IDisposable 패턴이다.

IDisposable 패턴이 구현된 객체는 using문을 이용할 수 있다.

using문을 이용하면 자동으로 해당 객체의 자원을 해제해주는 기능을 제공한다. (개발자에 의해 명시적 호출)

// using문을 벗어나면 자동적으로 foo.Dispose() 메서드 호출
// using문에 선언되는 객체가 Dispose 메서드가 없는 경우 컴파일 에러가 난다.
using(var foo = new Foo())
{
    //do something.
}

// using을 사용하지 않은 경우
try
{
    var foo = new Foo();
    // do something.
}
finally
{
    foo?.Dispose();
}

IDisposable만 구현해준다면 Finalizer를 정의안해도 상관없을 것 같지만 그렇지 않다.

MSDN에서 제공되는 IDisposable 패턴의 표준 소스에도 Finalizer가 있는 것을 확인할 수 있다.

using문을 이용하여 개발자가 명시적으로 호출하는 경우 자원을 제때 정리할 수 있지만, using문 호출을 잊어버린 경우 CLR에서 호출할 수 있도록 Fianlizer를 정의하여(암시적 호출) 자원을 해제해줌으로 써 리소스 누수를 막을 수 있다.

그렇기에 귀찮더라도 Finalizer 메서드도 함께 정의한다.

구현

기본적으로 객체에 IDisposable 인터페이스를 상속받으면 인텔리센스에서 MSDN이 제공하는 표준 IDisposable 패턴을 자동으로 구현할 수 있다. (대박)

idisposable

#region IDisposable Support
private bool disposedValue = false; // 중복 호출을 검색하려면

protected virtual void Dispose(bool disposing)
{
    if (!disposedValue)
    {
        if (disposing)
        {
            // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다.
            // 
        }

        // TODO: 관리되지 않는 리소스(관리되지 않는 개체)를 해제하고 아래의 종료자를 재정의합니다.
        // TODO: 큰 필드를 null로 설정합니다.

        disposedValue = true;
    }
}

// TODO: 위의 Dispose(bool disposing)에 관리되지 않는 리소스를 해제하는 코드가 포함되어 있는 경우에만 종료자를 재정의합니다.
// ~Foo() {
//   // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
//   Dispose(false);
// }

// 삭제 가능한 패턴을 올바르게 구현하기 위해 추가된 코드입니다.
public void Dispose()
{
    // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
    Dispose(true);
    // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다.
    // GC.SuppressFinalize(this);
}
#endregion

위 소스는 MSDN에서 제공하는 표준 IDisposable 패턴의 코드이다.

인터페이스로 정의된 Dispose 메서드 호출 시 재정의된 Dispose 메서드에 true로 인자를 넘겨주고 있는데, 해당 인자로 인해 if (disposing) 조건을 타게된다. 이 조건은 관리형 리소스를 해제해주는 부분인데, 보통 byte[]와 같은 큰 객체의 참조를 끊어주기(GC의 루트 참조를 빨리 끊어버리기 위함) 위해 해당 필드(속성)에 null을 대입해주는 것이 좋다고 한다.


Reference

MSDN - IDisposable 인터페이스

Dispose 패턴