IDisposable Rozhraní

Definice

Poskytuje mechanismus pro uvolnění nespravovaných prostředků.

public interface class IDisposable
public interface IDisposable
[System.Runtime.InteropServices.ComVisible(true)]
public interface IDisposable
type IDisposable = interface
[<System.Runtime.InteropServices.ComVisible(true)>]
type IDisposable = interface
Public Interface IDisposable
Odvozené
Atributy

Příklady

Následující příklad ukazuje, jak vytvořit třídu prostředků, která implementuje IDisposable rozhraní.

using System;
using System.ComponentModel;

// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.

public class DisposeExample
{
    // A base class that implements IDisposable.
    // By implementing IDisposable, you are announcing that
    // instances of this type allocate scarce resources.
    public class MyResource: IDisposable
    {
        // Pointer to an external unmanaged resource.
        private IntPtr handle;
        // Other managed resource this class uses.
        private Component component = new Component();
        // Track whether Dispose has been called.
        private bool disposed = false;

        // The class constructor.
        public MyResource(IntPtr handle)
        {
            this.handle = handle;
        }

        // Implement IDisposable.
        // Do not make this method virtual.
        // A derived class should not be able to override this method.
        public void Dispose()
        {
            Dispose(disposing: true);
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SuppressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize(this);
        }

        // Dispose(bool disposing) executes in two distinct scenarios.
        // If disposing equals true, the method has been called directly
        // or indirectly by a user's code. Managed and unmanaged resources
        // can be disposed.
        // If disposing equals false, the method has been called by the
        // runtime from inside the finalizer and you should not reference
        // other objects. Only unmanaged resources can be disposed.
        protected virtual void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if(!this.disposed)
            {
                // If disposing equals true, dispose all managed
                // and unmanaged resources.
                if(disposing)
                {
                    // Dispose managed resources.
                    component.Dispose();
                }

                // Call the appropriate methods to clean up
                // unmanaged resources here.
                // If disposing is false,
                // only the following code is executed.
                CloseHandle(handle);
                handle = IntPtr.Zero;

                // Note disposing has been done.
                disposed = true;
            }
        }

        // Use interop to call the method necessary
        // to clean up the unmanaged resource.
        [System.Runtime.InteropServices.DllImport("Kernel32")]
        private extern static Boolean CloseHandle(IntPtr handle);

        // Use C# finalizer syntax for finalization code.
        // This finalizer will run only if the Dispose method
        // does not get called.
        // It gives your base class the opportunity to finalize.
        // Do not provide finalizer in types derived from this class.
        ~MyResource()
        {
            // Do not re-create Dispose clean-up code here.
            // Calling Dispose(disposing: false) is optimal in terms of
            // readability and maintainability.
            Dispose(disposing: false);
        }
    }
    public static void Main()
    {
        // Insert code here to create
        // and use the MyResource object.
    }
}
// The following example demonstrates how to create
// a resource class that implements the IDisposable interface
// and the IDisposable.Dispose method.
open System
open System.ComponentModel
open System.Runtime.InteropServices

// Use interop to call the method necessary
// to clean up the unmanaged resource.
[<DllImport "Kernel32">]
extern Boolean CloseHandle(nativeint handle)

// A base class that implements IDisposable.
// By implementing IDisposable, you are announcing that
// instances of this type allocate scarce resources.
type MyResource(handle: nativeint) =
    // Pointer to an external unmanaged resource.
    let mutable handle = handle

    // Other managed resource this class uses.
    let comp = new Component()
    
    // Track whether Dispose has been called.
    let mutable disposed = false

    // Implement IDisposable.
    // Do not make this method virtual.
    // A derived class should not be able to override this method.
    interface IDisposable with
        member this.Dispose() =
            this.Dispose true
            // This object will be cleaned up by the Dispose method.
            // Therefore, you should call GC.SuppressFinalize to
            // take this object off the finalization queue
            // and prevent finalization code for this object
            // from executing a second time.
            GC.SuppressFinalize this

    // Dispose(bool disposing) executes in two distinct scenarios.
    // If disposing equals true, the method has been called directly
    // or indirectly by a user's code. Managed and unmanaged resources
    // can be disposed.
    // If disposing equals false, the method has been called by the
    // runtime from inside the finalizer and you should not reference
    // other objects. Only unmanaged resources can be disposed.
    abstract Dispose: bool -> unit
    override _.Dispose(disposing) =
        // Check to see if Dispose has already been called.
        if not disposed then
            // If disposing equals true, dispose all managed
            // and unmanaged resources.
            if disposing then
                // Dispose managed resources.
                comp.Dispose()

            // Call the appropriate methods to clean up
            // unmanaged resources here.
            // If disposing is false,
            // only the following code is executed.
            CloseHandle handle |> ignore
            handle <- IntPtr.Zero

            // Note disposing has been done.
            disposed <- true


    // This finalizer will run only if the Dispose method
    // does not get called.
    // It gives your base class the opportunity to finalize.
    // Do not provide finalizer in types derived from this class.
    override this.Finalize() =
        // Do not re-create Dispose clean-up code here.
        // Calling Dispose(disposing: false) is optimal in terms of
        // readability and maintainability.
        this.Dispose false
Imports System.ComponentModel

' The following example demonstrates how to create
' a resource class that implements the IDisposable interface
' and the IDisposable.Dispose method.
Public Class DisposeExample

   ' A class that implements IDisposable.
   ' By implementing IDisposable, you are announcing that
   ' instances of this type allocate scarce resources.
   Public Class MyResource
      Implements IDisposable
      ' Pointer to an external unmanaged resource.
      Private handle As IntPtr
      ' Other managed resource this class uses.
      Private component As component
      ' Track whether Dispose has been called.
      Private disposed As Boolean = False

      ' The class constructor.
      Public Sub New(ByVal handle As IntPtr)
         Me.handle = handle
      End Sub

      ' Implement IDisposable.
      ' Do not make this method virtual.
      ' A derived class should not be able to override this method.
      Public Overloads Sub Dispose() Implements IDisposable.Dispose
         Dispose(disposing:=True)
         ' This object will be cleaned up by the Dispose method.
         ' Therefore, you should call GC.SupressFinalize to
         ' take this object off the finalization queue
         ' and prevent finalization code for this object
         ' from executing a second time.
         GC.SuppressFinalize(Me)
      End Sub

      ' Dispose(bool disposing) executes in two distinct scenarios.
      ' If disposing equals true, the method has been called directly
      ' or indirectly by a user's code. Managed and unmanaged resources
      ' can be disposed.
      ' If disposing equals false, the method has been called by the
      ' runtime from inside the finalizer and you should not reference
      ' other objects. Only unmanaged resources can be disposed.
      Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)
         ' Check to see if Dispose has already been called.
         If Not Me.disposed Then
            ' If disposing equals true, dispose all managed
            ' and unmanaged resources.
            If disposing Then
               ' Dispose managed resources.
               component.Dispose()
            End If

            ' Call the appropriate methods to clean up
            ' unmanaged resources here.
            ' If disposing is false,
            ' only the following code is executed.
            CloseHandle(handle)
            handle = IntPtr.Zero

            ' Note disposing has been done.
            disposed = True

         End If
      End Sub

      ' Use interop to call the method necessary
      ' to clean up the unmanaged resource.
      <System.Runtime.InteropServices.DllImport("Kernel32")> _
      Private Shared Function CloseHandle(ByVal handle As IntPtr) As [Boolean]
      End Function

      ' This finalizer will run only if the Dispose method
      ' does not get called.
      ' It gives your base class the opportunity to finalize.
      ' Do not provide finalize methods in types derived from this class.
      Protected Overrides Sub Finalize()
         ' Do not re-create Dispose clean-up code here.
         ' Calling Dispose(disposing:=False) is optimal in terms of
         ' readability and maintainability.
         Dispose(disposing:=False)
         MyBase.Finalize()
      End Sub
   End Class

   Public Shared Sub Main()
      ' Insert code here to create
      ' and use the MyResource object.
   End Sub

End Class

Poznámky

Hlavním účelem použití IDisposable rozhraní je uvolnění nespravovaných prostředků. Garbage collector automaticky uvolní paměť přidělenou spravovanému objektu v okamžiku, kdy se tento objekt přestane používat. Nelze však předpovědět, kdy bude probíhat garbage collection. Správce paměti navíc nemá žádné znalosti o nespravovaných prostředcích, jako jsou popisovače oken, nebo otevřené soubory a proudy.

Dispose Pomocí metody tohoto rozhraní explicitně uvolnit nespravované prostředky ve spojení s uvolňováním paměti. Příjemce objektu může tuto metodu volat, pokud objekt již není potřeba.

Warning

Jedná se o zásadní změnu přidání IDisposable rozhraní do existující třídy. Vzhledem k tomu, že již existující spotřebitelé typu nemohou volat Dispose, nemůžete být jisti, že nespravované prostředky uchovávané vaším typem budou uvolněny.

Vzhledem k tomu, že implementace IDisposable.Dispose je volána příjemcem typu, když již instance nepotřebuje prostředky, které vlastní, měli byste buď zabalit spravovaný objekt do SafeHandle (doporučená alternativa), nebo byste měli přepsat Object.Finalize, aby se uvolnily nespravované prostředky v případě, že příjemce zapomene volat Dispose.

Podrobné informace o tom, jak se používají toto rozhraní a metoda Object.Finalize, najdete v tématech „Uvolňování paměti“ a „Implementace metody Dispose“.

Použití objektu, který implementuje IDisposable

Pokud vaše aplikace jednoduše používá objekt, který implementuje IDisposable rozhraní, měli byste po dokončení jeho použití volat implementaci objektu IDisposable.Dispose . V závislosti na programovacím jazyce to můžete udělat jedním ze dvou způsobů:

  • Pomocí jazykové konstrukce, jako je příkaz using v jazycích C# a Visual Basic, a příkaz use nebo funkce using v jazyce F#.
  • Zabalením volání implementace IDisposable.Dispose do try/finally bloku.

Note

Dokumentace pro typy, které implementují IDisposable, zahrnuje poznámku o této skutečnosti a připomíná volání jejich implementace Dispose.

Příkaz Using v jazycích C#, F# a Visual Basic

Pokud váš jazyk podporuje konstruktor, jako je příkaz using v jazyce C#, příkaz Using v jazyce Visual Basic nebo příkaz use v jazyce F#, můžete ho místo explicitního volání IDisposable.Dispose použít. Následující příklad používá tento přístup k definování WordCount třídy, která zachovává informace o souboru a počtu slov v něm.

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

Příkaz using (výraz use v jazyce F#) je ve skutečnosti syntaktické pohodlí. Kompilátor jazyka implementuje při kompilaci prostřední jazyk (IL) pro blok try/finally.

Další informace o using příkazu naleznete v tématu Using Statement nebo v tématu using Statement.

Blok Try/Finally v programování

Pokud programovací jazyk nepodporuje konstruktor, jako je příkaz using v jazyce C# nebo Visual Basic nebo use příkaz v jazyce F#, nebo pokud ho nechcete použít, můžete volat IDisposable.Dispose implementaci z finally bloku try/finally příkazu. Následující příklad nahrazuje using blok v předchozím příkladu blokemtry/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

Další informace o vzoru try/finally naleznete v tématu Try...Catch...Finally Příkaz, try-finally, try...finally Výraz, nebo try-finally Příkaz.

Implementovat IDisposable

Pokud váš typ používá nespravované prostředky přímo nebo pokud chcete použít uvolnitelné prostředky sami, měli byste implementovat IDisposable . Uživatelé vašeho typu mohou volat implementaci IDisposable.Dispose k uvolnění prostředků, když už instanci nepotřebujete. Chcete-li zpracovat případy, ve kterých se jim nepodaří volat Dispose, měli byste použít třídu odvozenou z SafeHandle pro obalení nespravovaných prostředků, nebo byste měli přepsat Object.Finalize metodu pro typ odkazu. V obou případech použijete metodu Dispose k provedení čištění, které je potřeba po použití nespravovaných prostředků, jako je uvolnění, uvolání nebo resetování nespravovaných prostředků. Další informace o implementaci IDisposable.Dispose, viz Dispose(bool) přetížení metody.

Important

Pokud definujete základní třídu, která používá nespravované prostředky a které buď mají, nebo je pravděpodobné, že mají podtřídy, které by měly být uvolněny, měli byste implementovat metodu IDisposable.Dispose a poskytnout druhé přetížení Dispose, jak je popsáno v další části.

IDisposable: hierarchie dědičnosti

Základní třída s podtřídami, které by měly být uvolnitelné, musí implementovat IDisposable následujícím způsobem. Tento vzor byste měli použít pokaždé, když implementujete IDisposable na jakýkoli typ, který není sealed (NotInheritable v jazyce Visual Basic).

  • Měla by poskytovat jednu veřejnou, ne virtuální Dispose() metodu a chráněnou virtuální Dispose(Boolean disposing) metodu.
  • Metoda Dispose() musí volat Dispose(true) a mělo by potlačit finalizaci kvůli lepšímu výkonu.
  • Základní typ by neměl obsahovat žádné finalizátory.

Následující fragment kódu odráží vzor Dispose pro základní třídy. Předpokládá se, že váš typ nepřepíše metodu 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

Pokud přepíšete metodu Object.Finalize , měla by vaše třída implementovat následující vzor.

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

Podtřídy by měly implementovat model na jedno použití následujícím způsobem:

  • Musí přepsat Dispose(Boolean) a volat implementaci základní třídy Dispose(Boolean) .
  • Mohou poskytnout finalizaci, pokud je to potřeba. Finalizátor musí zavolat Dispose(false).

Všimněte si, že odvozené třídy samy o sobě neimplementují IDisposable rozhraní a nezahrnují bezparametrovou Dispose metodu. Přepíší pouze metodu základní třídy Dispose(Boolean) .

Následující fragment kódu odráží vzor Dispose pro odvozené třídy. Předpokládá se, že váš typ nepřepíše metodu 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

Metody

Name Description
Dispose()

Provádí úlohy definované aplikací související s uvolněním, uvolněním nebo resetováním nespravovaných prostředků.

Platí pro

Viz také