Dispose 메서드 구현

업데이트: 2007년 11월

개체 삭제 패턴은 삭제 패턴이라고도 하며 개체의 수명에 순서를 적용합니다.

형식의 Dispose메서드는 형식에 포함된 모든 리소스는 물론 부모 형식의 Dispose 메서드를 호출하여 기본 형식에서 소유하는 모든 리소스도 해제해야 합니다. 부모 형식의 Dispose 메서드는 해당 형식에서 소유하는 모든 리소스를 해제하고 부모 형식의 Dispose 메서드를 호출해야 합니다. 이 패턴은 기본 형식의 계층 구조 전체에 전파됩니다. 리소스가 항상 적절하게 정리되게 하려면 예외를 throw하지 않고 Dispose 메서드를 여러 번 호출해야 합니다.

관리되는 리소스(예: 배열)는 가비지 수집기에 의해 자동으로 회수되므로 이러한 리소스만 사용하는 형식에서 Dispose 메서드를 구현하면 성능상의 이점이 없습니다. Dispose 메서드는 주로 네이티브 리소스를 사용하는 관리되는 개체 및 .NET Framework에 노출되는 COM 개체에서 사용하는 것이 좋습니다. 네이티브 리소스(예: FileStream 클래스)를 사용하는 관리되는 개체는 IDisposable 인터페이스를 구현합니다.

중요:

C++ 프로그래머는 이 항목을 사용해서는 안 됩니다. 그 대신, Destructors and Finalizers in Visual C++를 참조하십시오. .NET Framework 버전 2.0에서 C++ 컴파일러는 리소스의 명확한 삭제 구현은 지원하지만 Dispose 메서드의 직접 구현은 허용하지 않습니다.

Dispose 메서드는 삭제하는 개체에 대해 SuppressFinalize 메서드를 호출해야 합니다. 개체가 현재 종료 큐에 있는 경우 SuppressFinalize 메서드를 호출하면 Finalize 메서드가 호출되지 않습니다. 앞에서 설명했듯이 Finalize 메서드를 실행하면 성능이 저하됩니다. 따라서 Dispose 메서드를 통해 개체 정리 작업이 이미 완료된 경우에는 가비지 수집기에서 개체의 Finalize 메서드를 호출할 필요가 없습니다.

GC.KeepAlive 메서드의 코드 예제에서는 적극적인 가비지 수집으로 인해, 회수된 개체의 멤버가 아직 실행되는 동안 종료자가 실행되게 할 수 있는 방법을 보여 줍니다. Dispose 메서드를 오래 실행한 후에는 KeepAlive 메서드를 호출하는 것이 좋습니다.

예제

다음 코드 예제에서는 관리되지 않는 리소스를 캡슐화하는 클래스에 대해 Dispose 메서드를 구현하는 데 유용한 디자인 패턴을 보여 줍니다.

리소스 클래스는 일반적으로 복잡한 네이티브 클래스나 API에서 파생되므로 적절하게 사용자 지정되어야 합니다. 이 코드 패턴을 참조하여 리소스 클래스를 만든 후 캡슐화한 리소스를 기준으로 필요한 경우 사용자 지정합니다.

Imports System
Imports System.IO
Class Program

    Public Shared Sub Main()
        Try
            ' Initialize a Stream resource to pass 
            ' to the DisposableResource class.
           Console.Write("Enter filename and its path: ")
            Dim fileSpec As String = Console.ReadLine
            Dim fs As FileStream = File.OpenRead(fileSpec)
            Dim TestObj As DisposableResource = New DisposableResource(fs)

            ' Use the resource.
            TestObj.DoSomethingWithResource()

            ' Dispose theresource.
            TestObj.Dispose()

        Catch e As FileNotFoundException
            Console.WriteLine(e.Message)
        End Try
    End Sub
End Class

' This class shows how to use a disposable resource.
' The resource is first initialized and passed to
' the constructor, but it could also be
' initialized in the constructor.
' The lifetime of the resource does not 
' exceed the lifetime of this instance.
' This type does not need a finalizer because it does not
' directly create a native resource like a file handle
' or memory in the unmanaged heap.
Public Class DisposableResource
    Implements IDisposable

    Private _resource As Stream

    Private _disposed As Boolean

    ' The stream passed to the constructor
    ' must be readable and not null.
    Public Sub New(ByVal stream As Stream)
        MyBase.New()
        If (stream Is Nothing) Then
            Throw New ArgumentNullException("Stream is null.")
        End If
        If Not stream.CanRead Then
            Throw New ArgumentException("Stream must be readable.")
        End If
        _resource = stream
        Dim objTypeName As String = _resource.GetType.ToString
        _disposed = False
    End Sub

    ' Demonstrates using the resource.
    ' It must not be already disposed.
    Public Sub DoSomethingWithResource()
        If _disposed Then
            Throw New ObjectDisposedException("Resource was disposed.")
        End If

        ' Show the number of bytes.
        Dim numBytes As Integer = CType(_resource.Length, Integer)
        Console.WriteLine("Number of bytes: {0}", numBytes.ToString)
    End Sub

    Public Overloads Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)

        ' Use SupressFinalize in case a subclass
        ' of this type implements a finalizer.
        GC.SuppressFinalize(Me)
    End Sub

    Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
        If Not _disposed Then

            ' If you need thread safety, use a lock around these 
            ' operations, as well as in your methods that use the resource.
            If disposing Then
                If (Not (_resource) Is Nothing) Then
                    _resource.Dispose()
                End If
                Console.WriteLine("Object disposed.")
            End If

            ' Indicates that the instance has been disposed.
            _resource = Nothing
            _disposed = True
        End If
    End Sub
End Class
using System;
using System.IO;

class Program
{

    static void Main()
    {
        try
        {
            // Initialize a Stream resource to pass 
            // to the DisposableResource class.
            Console.Write("Enter filename and its path: ");
            string fileSpec = Console.ReadLine();
            FileStream fs = File.OpenRead(fileSpec);
            DisposableResource TestObj = new DisposableResource(fs);

            // Use the resource.
            TestObj.DoSomethingWithResource();

            // Dispose the resource.
            TestObj.Dispose();

        }
        catch (FileNotFoundException e)
        {
            Console.WriteLine(e.Message);
        }
    }
}


// This class shows how to use a disposable resource.
// The resource is first initialized and passed to
// the constructor, but it could also be
// initialized in the constructor.
// The lifetime of the resource does not 
// exceed the lifetime of this instance.
// This type does not need a finalizer because it does not
// directly create a native resource like a file handle
// or memory in the unmanaged heap.

public class DisposableResource : IDisposable
{

    private Stream _resource;  
    private bool _disposed;

    // The stream passed to the constructor 
    // must be readable and not null.
    public DisposableResource(Stream stream)
    {
        if (stream == null)
            throw new ArgumentNullException("Stream in null.");
        if (!stream.CanRead)
            throw new ArgumentException("Stream must be readable.");

        _resource = stream;

        _disposed = false;
    }

    // Demonstrates using the resource. 
    // It must not be already disposed.
    public void DoSomethingWithResource() {
        if (_disposed)
            throw new ObjectDisposedException("Resource was disposed.");

        // Show the number of bytes.
        int numBytes = (int) _resource.Length;
        Console.WriteLine("Number of bytes: {0}", numBytes.ToString());
    }


    public void Dispose() 
    {
        Dispose(true);

        // Use SupressFinalize in case a subclass
        // of this type implements a finalizer.
        GC.SuppressFinalize(this);      
    }

    protected virtual void Dispose(bool disposing)
    {
        // If you need thread safety, use a lock around these 
        // operations, as well as in your methods that use the resource.
        if (!_disposed)
        {
            if (disposing) {
                if (_resource != null)
                    _resource.Dispose();
                    Console.WriteLine("Object disposed.");
            }

            // Indicate that the instance has been disposed.
            _resource = null;
            _disposed = true;   
        }
    }
}

참고 항목

개념

Finalize 메서드 재정의

참조

SuppressFinalize

Destructors and Finalizers in Visual C++

Finalize 및 Dispose를 구현하여 관리되지 않는 리소스 정리