System.IDisposable 인터페이스

이 문서에서는 이 API에 대한 참조 설명서에 대한 추가 설명서를 제공합니다.

인터페이스의 IDisposable 기본 사용은 관리되지 않는 리소스를 해제하는 것입니다. 가비지 수집기는 해당 개체가 더 이상 사용되지 않을 때 관리되는 개체에 할당된 메모리를 자동으로 해제합니다. 그러나 가비지 수집이 발생할 시기를 예측할 수 없습니다. 또한 가비지 수집기는 창 핸들 또는 열린 파일 및 스트림과 같은 관리되지 않는 리소스에 대해 전혀 알지 않습니다.

이 인터페이스의 메서드를 Dispose 사용하여 가비지 수집기와 함께 관리되지 않는 리소스를 명시적으로 해제합니다. 개체가 더 이상 필요하지 않은 경우 개체 소비자가 이 메서드를 호출할 수 있습니다.

Warning

기존 클래스에 인터페이스를 추가하는 IDisposable 것은 호환성이 손상되는 변경입니다. 형식의 기존 소비자는 호출 Dispose할 수 없으므로 형식에서 보유하는 관리되지 않는 리소스가 릴리스될 것이라고 확신할 수 없습니다.

IDisposable.Dispose 인스턴스가 소유한 리소스가 더 이상 필요하지 않은 경우 형식의 소비자가 구현을 호출하기 때문에 관리되는 개체 SafeHandle 를 래핑하거나(권장되는 대안) 소비자가 호출Dispose을 잊어버린 경우 관리되지 않는 리소스를 해제하도록 재정 Object.Finalize 의해야 합니다.

Important

.NET Framework에서 C++ 컴파일러는 리소스의 결정적 삭제를 지원하며 메서드의 직접 구현을 Dispose 허용하지 않습니다.

이 인터페이스와 Object.Finalize 메서드를 사용하는 방법에 대한 자세한 내용은 가비지 수집Dispose 메서드 구현 항목을 참조하세요.

IDisposable을 구현하는 개체 사용

앱에서 인터페이스를 구현 IDisposable 하는 개체만 사용하는 경우 사용이 완료되면 개체의 IDisposable.Dispose 구현을 호출해야 합니다. 프로그래밍 언어에 따라 다음 두 가지 방법 중 하나로 이 작업을 수행할 수 있습니다.

  • C# 및 Visual Basic의 using 문과 같은 언어 구문과 F#의 use 문 또는 using 함수를 사용합니다.
  • 블록에서 구현 try/finally 에 대한 호출을 IDisposable.Dispose 래핑합니다.

참고 항목

구현 IDisposable 하는 형식에 대한 설명서는 해당 사실을 확인하고 해당 구현을 호출 Dispose 하기 위한 미리 알림을 포함합니다.

C#, F#, Visual Basic Using 문

언어가 C#의 using 문, Visual Basic의 Using 문 또는 F#의 use 문과 같은 구문을 지원하는 경우 명시적으로 자신을 호출 IDisposable.Dispose 하는 대신 사용할 수 있습니다. 다음 예제에서는 파일에 대한 정보와 파일의 단어 수를 유지하는 클래스를 정의하는 WordCount 데 이 방법을 사용합니다.

using System;
using System.IO;
using System.Text.RegularExpressions;

public class WordCount
{
    private String filename = String.Empty;
    private int nWords = 0;
    private String pattern = @"\b\w+\b";

    public WordCount(string filename)
    {
        if (!File.Exists(filename))
            throw new FileNotFoundException("The file does not exist.");

        this.filename = filename;
        string txt = String.Empty;
        using (StreamReader sr = new StreamReader(filename))
        {
            txt = sr.ReadToEnd();
        }
        nWords = Regex.Matches(txt, pattern).Count;
    }

    public string FullName
    { get { return filename; } }

    public string Name
    { get { return Path.GetFileName(filename); } }

    public int Count
    { get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions

type WordCount(filename) =
    let txt = 
        if File.Exists filename |> not then
            raise (FileNotFoundException "The file does not exist.")

        use sr = new StreamReader(filename)
        sr.ReadToEnd()

    let pattern = @"\b\w+\b"
    
    let nWords = Regex.Matches(txt, pattern).Count

    member _.FullName = filename

    member _.Name = Path.GetFileName filename

    member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions

Public Class WordCount
   Private filename As String
   Private nWords As Integer
   Private pattern As String = "\b\w+\b" 

   Public Sub New(filename As String)
      If Not File.Exists(filename) Then
         Throw New FileNotFoundException("The file does not exist.")
      End If   
      
      Me.filename = filename
      Dim txt As String = String.Empty
      Using sr As New StreamReader(filename)
         txt = sr.ReadToEnd()
      End Using
      nWords = Regex.Matches(txt, pattern).Count
   End Sub
   
   Public ReadOnly Property FullName As String
      Get
         Return filename
      End Get   
   End Property
   
   Public ReadOnly Property Name As String
      Get
         Return Path.GetFileName(filename)
      End Get   
   End Property
   
   Public ReadOnly Property Count As Integer
      Get
         Return nWords
      End Get
   End Property
End Class

using 문(useF#의 식)은 실제로 구문 편의성입니다. 컴파일 시 언어 컴파일러는 블록에 대한 IL(중간 언어)을 try/finally 구현합니다.

문에 대한 using 자세한 내용은 Using 문 또는 using Statement 항목을 참조하세요.

Try/Finally 블록

프로그래밍 언어가 C# 또는 Visual Basic의 문이나 F#의 문과 같은 구문을 지원하지 않거나 사용하지 않으려는 경우 문 블록tryfinally/에서 finally 구현을 호출 IDisposable.Dispose 할 수 있습니다.usinguse 다음 예제에서는 이전 예제의 using 블록을 블록으로 try/finally 바꿉니다.

using System;
using System.IO;
using System.Text.RegularExpressions;

public class WordCount2
{
    private String filename = String.Empty;
    private int nWords = 0;
    private String pattern = @"\b\w+\b";

    public WordCount2(string filename)
    {
        if (!File.Exists(filename))
            throw new FileNotFoundException("The file does not exist.");

        this.filename = filename;
        string txt = String.Empty;
        StreamReader? sr = null;
        try
        {
            sr = new StreamReader(filename);
            txt = sr.ReadToEnd();
        }
        finally
        {
            if (sr != null) sr.Dispose();
        }
        nWords = Regex.Matches(txt, pattern).Count;
    }

    public string FullName
    { get { return filename; } }

    public string Name
    { get { return Path.GetFileName(filename); } }

    public int Count
    { get { return nWords; } }
}
open System.IO
open System.Text.RegularExpressions

type WordCount2(filename) =
    let txt = 
        if File.Exists filename |> not then
            raise (FileNotFoundException "The file does not exist.")

        let sr = new StreamReader(filename)
        try
            sr.ReadToEnd()
        finally
            sr.Dispose()

    let pattern = @"\b\w+\b"
    
    let nWords = Regex.Matches(txt, pattern).Count

    member _.FullName = filename

    member _.Name = Path.GetFileName filename

    member _.Count = nWords
Imports System.IO
Imports System.Text.RegularExpressions

Public Class WordCount2
   Private filename As String
   Private nWords As Integer
   Private pattern As String = "\b\w+\b" 

   Public Sub New(filename As String)
      If Not File.Exists(filename) Then
         Throw New FileNotFoundException("The file does not exist.")
      End If   
      
      Me.filename = filename
      Dim txt As String = String.Empty
      Dim sr As StreamReader = Nothing
      Try
         sr = New StreamReader(filename)
         txt = sr.ReadToEnd()
      Finally
         If sr IsNot Nothing Then sr.Dispose() 
      End Try
      nWords = Regex.Matches(txt, pattern).Count
   End Sub
   
   Public ReadOnly Property FullName As String
      Get
         Return filename
      End Get   
   End Property
   
   Public ReadOnly Property Name As String
      Get
         Return Path.GetFileName(filename)
      End Get   
   End Property
   
   Public ReadOnly Property Count As Integer
      Get
         Return nWords
      End Get
   End Property
End Class

패턴에 대한finallytry/자세한 내용은 Try... 잡을... 마지막으로 문, try-finally, try... finally Expression 또는 try-finally 문입니다.

IDisposable 구현

형식이 관리되지 않는 리소스를 직접 사용하거나 삭제 가능한 리소스를 직접 사용하려는 경우 구현 IDisposable 해야 합니다. 형식의 소비자는 인스턴스가 더 이상 필요하지 않을 때 구현을 호출 IDisposable.Dispose 하여 리소스를 해제할 수 있습니다. 호출 Dispose에 실패한 경우를 처리하려면 관리되지 않는 리소스를 래핑하기 위해 파생된 SafeHandle 클래스를 사용하거나 참조 형식에 대한 메서드를 재정의 Object.Finalize 해야 합니다. 두 경우 모두 관리되지 않는 리소스를 사용하거나, 해제하거나, 관리되지 않는 리소스를 다시 설정하는 등 관리되지 않는 리소스를 사용한 후 필요한 모든 클린를 수행하는 데 이 메서드를 사용합니다Dispose. 구현에 IDisposable.Dispose대한 자세한 내용은 Dispose(bool) 메서드 오버로드를 참조하세요.

Important

관리되지 않는 리소스를 사용하고 삭제해야 하는 서브클래스가 있거나 있을 가능성이 있는 기본 클래스를 정의하는 경우 다음 섹션에서 설명한 대로 메서드를 구현 IDisposable.Dispose 하고 두 번째 오버로드 Dispose를 제공해야 합니다.

IDisposable 및 상속 계층 구조

삭제 가능해야 하는 서브클래스가 있는 기본 클래스는 다음과 같이 구현 IDisposable 해야 합니다. Visual Basic에서는 그렇지 않은 sealedNotInheritable 형식에서 구현 IDisposable 할 때마다 이 패턴을 사용해야 합니다.

  • 하나의 공용, 비 가상 Dispose() 메서드 및 보호된 가상 Dispose(Boolean disposing) 메서드를 제공해야 합니다.
  • 메서드는 Dispose() 호출 Dispose(true) 해야 하며 성능에 대한 종료를 표시하지 않아야 합니다.
  • 기본 형식에는 종료자가 포함되지 않아야 합니다.

다음 코드 조각은 기본 클래스에 대한 삭제 패턴을 반영합니다. 형식이 메서드를 재정의하지 않는다고 가정합니다 Object.Finalize .

using System;
using System.IO;
using System.Runtime.InteropServices;

class BaseClass1 : IDisposable
{
    // Flag: Has Dispose already been called?
    bool disposed = false;
    // Instantiate a FileStream instance.
    FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            fs.Dispose();
            // Free any other managed objects here.
            //
        }

        disposed = true;
    }
}
open System
open System.IO

type BaseClass1() =
    // Flag: Has Dispose already been called?
    let mutable disposed = false

    // Instantiate a FileStream instance.
    let fs = new FileStream("test.txt", FileMode.OpenOrCreate)

    interface IDisposable with
        // Public implementation of Dispose pattern callable by consumers.
        member this.Dispose() =
            this.Dispose true
            GC.SuppressFinalize this

    // Implementation of Dispose pattern.
    abstract Dispose: bool -> unit
    override _.Dispose(disposing) =
        if not disposed then
            if disposing then
                fs.Dispose()
                // Free any other managed objects here.
            disposed <- true
Imports System.IO
Imports System.Runtime.InteropServices

Class BaseClass1 : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a FileStream instance.
   Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(disposing:=True)
      GC.SuppressFinalize(Me)
   End Sub

   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         fs.Dispose()
         ' Free any other managed objects here.
         '
      End If

      disposed = True
   End Sub
End Class

메서드를 재정의 Object.Finalize 하는 경우 클래스는 다음 패턴을 구현해야 합니다.

using System;

class BaseClass2 : IDisposable
{
    // Flag: Has Dispose already been called?
    bool disposed = false;

    // Public implementation of Dispose pattern callable by consumers.
    public void Dispose()
    {
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    // Protected implementation of Dispose pattern.
    protected virtual void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            // Free any other managed objects here.
            //
        }

        // Free any unmanaged objects here.
        //
        disposed = true;
    }

    ~BaseClass2()
    {
        Dispose(disposing: false);
    }
}
open System

type BaseClass2() =
    // Flag: Has Dispose already been called?
    let mutable disposed = false

    interface IDisposable with
        // Public implementation of Dispose pattern callable by consumers.
        member this.Dispose() =
            this.Dispose true
            GC.SuppressFinalize this

    // Implementation of Dispose pattern.
    abstract Dispose: bool -> unit
    override _.Dispose(disposing) =
        if not disposed then
            if disposing then
                // Free any other managed objects here.
                ()

            // Free any unmanaged objects here.
            disposed <- true

    override this.Finalize() =
        this.Dispose false
Class BaseClass : Implements IDisposable
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False

   ' Public implementation of Dispose pattern callable by consumers.
   Public Sub Dispose() _
              Implements IDisposable.Dispose
      Dispose(disposing:=True)
      GC.SuppressFinalize(Me)
   End Sub

   ' Protected implementation of Dispose pattern.
   Protected Overridable Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         ' Free any other managed objects here.
         '
      End If

      ' Free any unmanaged objects here.
      '
      disposed = True
   End Sub

   Protected Overrides Sub Finalize()
      Dispose(disposing:=False)
   End Sub
End Class

서브클래스는 다음과 같이 삭제 가능한 패턴을 구현해야 합니다.

  • 기본 클래스 Dispose(Boolean) 구현을 재정 Dispose(Boolean) 의하고 호출해야 합니다.
  • 필요한 경우 종료자를 제공할 수 있습니다. 종료자는 을 호출 Dispose(false)해야 합니다.

파생 클래스 자체는 인터페이스를 구현 IDisposable 하지 않으며 매개 변수가 없는 Dispose 메서드를 포함하지 않습니다. 기본 클래스 Dispose(Boolean) 메서드만 재정의합니다.

다음 코드 조각은 파생 클래스에 대한 삭제 패턴을 반영합니다. 형식이 메서드를 재정의하지 않는다고 가정합니다 Object.Finalize .

using System;
using System.IO;
using System.Runtime.InteropServices;

class MyDerivedClass : MyBaseClass
{
    // Flag: Has Dispose already been called?
    bool disposed = false;
    // Instantiate a FileStream instance.
    FileStream fs = new FileStream("test.txt", FileMode.OpenOrCreate);

    // Protected implementation of Dispose pattern.
    protected override void Dispose(bool disposing)
    {
        if (disposed)
            return;

        if (disposing)
        {
            fs.Dispose();
            // Free any other managed objects here.
            //
        }

        // Free any unmanaged objects here.
        //

        disposed = true;
        // Call base class implementation.
        base.Dispose(disposing);
    }
}
open Microsoft.Win32.SafeHandles
open System

type MyDerivedClass() =
    inherit MyBaseClass()
    
    // Flag: Has Dispose already been called?
    let mutable disposed = false
    // Instantiate a FileStream instance.
    let fs = new FileStream("test.txt", FileMode.OpenOrCreate)

    // Implementation of Dispose pattern.
    override _.Dispose(disposing) =
        if not disposed then
            if disposing then
                fs.Dispose()
                // Free any other managed objects here.

            // Free any unmanaged objects here.
            disposed <- true
            // Call base class implementation.
            base.Dispose disposing
Imports System.IO
Imports System.Runtime.InteropServices

Class DerivedClass2 : Inherits BaseClass2
   ' Flag: Has Dispose already been called?
   Dim disposed As Boolean = False
   ' Instantiate a FileStream instance.
   Dim fs As FileStream = New FileStream("test.txt", FileMode.OpenOrCreate)

   ' Protected implementation of Dispose pattern.
   Protected Overrides Sub Dispose(disposing As Boolean)
      If disposed Then Return

      If disposing Then
         fs.Dispose()
         ' Free any other managed objects here.
         '
      End If

      ' Free any unmanaged objects here.
      '
      disposed = True

      ' Call base class implementation.
      MyBase.Dispose(disposing)
   End Sub
End Class