본문 바로가기
우아한 코딩

C# 표준 Dispose 패턴을 구현하자

by 피크인사이트 2024. 4. 2.
반응형

안녕하세요!

이번 포스팅에서는 프로그래밍에서 중요한 개념 중 하나인 "표준 Dispose 패턴"에 대해 알아보겠습니다

표준 Dispose 패턴 구현

1. Dispose 패턴이란?

먼저 Dispose 패턴은 .NET에서 자원을 명시적으로 해제하는 방법을 제공합니다.

주로 비관리 자원을 사용할 때 사용되며, 메모리 누수를 방지하여 시스템 성능을 향상시킵니다.

또한, 이 패턴을 구현하면 개발자가 직접 자원을 관리할 수 있기 때문에 프로그램의 안정성과 효율성을 높일 수 있습니다.

아래는  Dispose 패턴을 사용한 예시코드입니다.

public class MyResource : IDisposable
{
    private bool disposed = false;

   // 인터페이스//
    public void Dispose()
    {
        Dispose(true); 
        GC.SuppressFinalize(this); //
    }

    // Dispose 메서드의 구현
    protected virtual void Dispose(bool disposings)
    {
        if (!disposed)    {
            if (disposings)    {
                // 관리자원 해제
            }
            
            // 비관리 자원 해제
            disposed = true;
        }
    }

    // Finalizer
    ~MyResource()
    {
        Dispose(false);
    }
}

 

2. 표준 Dispose 패턴의 구성 요소

표준 Dispose 패턴은 보통 IDisposable 인터페이스와 Dispose 메서드를 사용하여 구현됩니다.

IDisposable 인터페이스를 구현하면 Dispose 메서드를 정의할 수 있으며, 이 Dispose  메서드에서 자원을 해제합니다.

아래 예시코드와 같이 Dispose 메서드는 개발자가 직접 호출하여 자원을 해제할 수 있습니다.

public interface IDisposable
{
    void Dispose();
}

 

3. Dispose 메서드의 구현

Dispose 메서드에서는 비관리 자원을 해제하고, 필요한 경우 관리되는 자원도 해제합니다.

Dispose 메서드는 여러 번 호출될 수 있으므로 이를 고려하여 구현해야 합니다.

Dispose 메서드를 호출한 후에는 해당 객체를 더 이상 사용하지 않아야 하며,

이후에 해당 객체에 대한 참조를 해제하는 것이 좋습니다.

public void Dispose()
{
   //Dispose...
    Dispose(true);
    GC.SuppressFinalize(this); 
}
//자원 해제
protected virtual void Dispose(bool disposings)
{
    if (!disposed)  {        
        if (disposings)
        {
            // 관리 자원 해제
        }
        
        // 비관리 자원 해제
        disposed = true;
    }
}

 

위의 코드 예시에서는 IDisposable 인터페이스를 구현하고 Dispose 메서드를 정의하는 방법을 보여줍니다.

Dispose 메서드는 관리되는 자원과 비관리 자원을 모두 해제하는 역할을 합니다.

또한 Dispose 메서드는 재귀적으로 호출되지 않도록 하기 위해 disposings 매개변수를 사용하여 이를 제어합니다.

 

4. using 문을 활용한 Dispose 패턴

다음은 using 문을 사용하여 Dispose 패턴을 더욱 간편하게 사용하는 방법을 살펴보겠습니다.

using 문을 사용하면 아래 예시처럼 Dispose 메서드를 명시적으로 호출하지 않아도 자동으로 호출됩니다.

using (MyResource resource = new MyResource())
{
    // 자원 사용
} // using 블록을 빠져나오면 자원이 자동으로 해제됨

 

5. 파생 클래스에서의 Dispose 패턴 구현

아래 코드는 파생 클래스에서 Dispose 패턴을 구현한 코드입니다.

Dispose 메서드를 재정의하는 경우에는 기반 클래스의 Dispose 메서드를 명시적으로 호출하는 것을 주의해야 합니다.

 

public class DerivedResource : MyResource
{
    private bool disposed = false;

    protected override void Dispose(bool disposings)
    {   //
        if (!disposed)
        {
            if (disposings)
            {
            // 파생 클래스에서 관리되는 자원 해제
            }

            // 기반 클래스의 Dispose 호출
            base.Dispose(disposings);

            disposed = true;
        }
    }
}

 

6. Finalize 메서드와의 관계

Dispose 패턴과 Finalize 메서드 간의 관계에 대해 살펴봅니다.

Dispose 메서드를 사용하여 자원을 명시적으로 해제하는 것이 메모리 누수를 방지하고 성능을 향상시키는데 도움이 되지만, Finalize 메서드도 함께 고려해야 합니다.

~MyResource()
{
    Dispose(false);
}

위 코드에서는 Finalize 메서드 내에서 Dispose 메서드를 호출하고 있습니다.

여기서 인자로는 false를 전달하여, Dispose 메서드가 Finalize 메서드에서 호출되었음을 나타냅니다.

Finalize 메서드 내에서는 관리되는 자원을 해제하지 않고, 오직 비관리 자원만을 해제하는 것이 좋습니다.

이렇게 함으로써 가비지 컬렉터가 수거되는 객체의 비관리 자원을 해제할 수 있습니다.


마치며

지금까지 살펴본 바와 같이 Dispose 패턴을 구현하는 것은 프로그램 코드의 품질을 높이고 시스템의 성능 향상에도 중요한 역할을 합니다.

따라서 효율적인 자원 관리를 위해 Dispose 패턴을 잘 활용하여 안정적인 코드를 작성하시길 바라며 마치겠습니다.

감사합니다.

반응형