Delen via


System.IDisposable interface

In dit artikel vindt u aanvullende opmerkingen in de referentiedocumentatie voor deze API.

Het primaire gebruik van de IDisposable interface is het vrijgeven van onbeheerde resources. De garbagecollector geeft automatisch het geheugen vrij dat is toegewezen aan een beheerd object wanneer dat object niet meer wordt gebruikt. Het is echter niet mogelijk om te voorspellen wanneer garbagecollection plaatsvindt. Bovendien heeft de garbagecollector geen kennis van onbeheerde resources, zoals venstergrepen, of open bestanden en stromen.

Gebruik de Dispose methode van deze interface om niet-beheerde resources expliciet vrij te geven in combinatie met de garbagecollector. De consument van een object kan deze methode aanroepen wanneer het object niet meer nodig is.

Waarschuwing

Het is een belangrijke wijziging om de IDisposable interface toe te voegen aan een bestaande klasse. Omdat bestaande consumenten van uw type niet kunnen worden aangeroepen Dispose, kunt u er niet zeker van zijn dat onbeheerde resources die door uw type worden bewaard, worden vrijgegeven.

Omdat de IDisposable.Dispose implementatie wordt aangeroepen door de consument van een type wanneer de resources die eigendom zijn van een exemplaar niet meer nodig zijn, moet u het beheerde object verpakken in een SafeHandle (het aanbevolen alternatief), of moet u overschrijven Object.Finalize naar gratis onbeheerde resources in het geval dat de consument vergeet aan te roepen Dispose.

Belangrijk

In .NET Framework ondersteunt de C++-compiler deterministische verwijdering van resources en staat de directe implementatie van de Dispose methode niet toe.

Zie de onderwerpen Garbagecollection en Het implementeren van een verwijderingsmethode voor een gedetailleerde bespreking van de manier waarop deze interface en de Object.Finalize methode worden gebruikt.

Een object gebruiken dat IDisposable implementeert

Als uw app gewoon gebruikmaakt van een object dat de IDisposable interface implementeert, moet u de implementatie van IDisposable.Dispose het object aanroepen wanneer u klaar bent met het gebruik ervan. Afhankelijk van uw programmeertaal kunt u dit op twee manieren doen:

  • Door gebruik te maken van een taalconstructie zoals de using instructie in C# en Visual Basic en de use instructie of using functie in F#.
  • Door de aanroep naar de IDisposable.Dispose implementatie in een try/finally blok te verpakken.

Notitie

Documentatie voor typen die implementeren IDisposable , houd er rekening mee dat feit en een herinnering bevatten om de Dispose implementatie aan te roepen.

De instructie C#, F# en Visual Basic Using

Als uw taal ondersteuning biedt voor een constructie zoals de using-instructie in C#, de using-instructie in Visual Basic of de use-instructie in F#, kunt u deze gebruiken in plaats van uzelf expliciet aan te roepen IDisposable.Dispose . In het volgende voorbeeld wordt deze methode gebruikt bij het definiëren van een WordCount klasse die informatie over een bestand en het aantal woorden erin bewaart.

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

De using instructie (use expressie in F#) is eigenlijk een syntactisch gemak. Tijdens het compileren implementeert de taalcompilator de tussenliggende taal (IL) voor een try/finally blok.

Zie de onderwerpen Using Statement of Using Statement (Instructie gebruiken) voor meer informatie over de using instructie.

Het blok Try/Finally

Als uw programmeertaal geen ondersteuning biedt voor een constructie zoals de using instructie in C# of Visual Basic, of de use instructie in F#, of als u deze liever niet gebruikt, kunt u de IDisposable.Dispose implementatie aanroepen vanuit het finally blok van een try/finally instructie. In het volgende voorbeeld wordt het using blok in het vorige voorbeeld vervangen door een try/finally blok.

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

Zie Try voor meer informatie over hetfinallytry/patroon... Vangen... Ten slotte instructie, try-finally, try... ten slotte expressie, of try-finally Statement.

IDisposable implementeren

U moet implementeren IDisposable als uw type rechtstreeks onbeheerde resources gebruikt of als u zelf wegwerpbronnen wilt gebruiken. De consumenten van uw type kunnen uw IDisposable.Dispose implementatie aanroepen naar gratis resources wanneer het exemplaar niet meer nodig is. Als u aanvragen wilt afhandelen waarin ze niet kunnen worden aangeroepen Dispose, moet u een klasse gebruiken die is afgeleid van het verpakken van SafeHandle de niet-beheerde resources, of moet u de Object.Finalize methode voor een verwijzingstype overschrijven. In beide gevallen gebruikt u de Dispose methode om de benodigde opschoning uit te voeren nadat u de niet-beheerde resources hebt gebruikt, zoals het vrijmaken, vrijgeven of opnieuw instellen van de onbeheerde resources. Zie de overbelasting van de methode Dispose(bool) voor meer informatie over het implementeren.IDisposable.Dispose

Belangrijk

Als u een basisklasse definieert die gebruikmaakt van niet-beheerde resources en die wel of waarschijnlijk subklassen hebben die moeten worden verwijderd, moet u de IDisposable.Dispose methode implementeren en een tweede overbelasting van Dispose, zoals besproken in de volgende sectie.

IDisposable en de overnamehiërarchie

Een basisklasse met subklassen die wegwerpbaar moeten zijn, moet als volgt worden geïmplementeerd IDisposable . U moet dit patroon gebruiken wanneer u implementeert IDisposable voor elk type dat niet sealed (NotInheritable in Visual Basic) is.

  • Het moet één openbare, niet-virtuele Dispose() methode en een beveiligde virtuele Dispose(Boolean disposing) methode bieden.
  • De Dispose() methode moet worden aangeroepen Dispose(true) en moet de voltooien voor prestaties onderdrukken.
  • Het basistype mag geen finalizers bevatten.

Het volgende codefragment weerspiegelt het verwijderingspatroon voor basisklassen. Hierbij wordt ervan uitgegaan dat uw type de Object.Finalize methode niet overschrijft.

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

Als u de Object.Finalize methode overschrijft, moet uw klasse het volgende patroon implementeren.

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

Subklassen moeten het wegwerppatroon als volgt implementeren:

  • Ze moeten de basisklasse-implementatie Dispose(Boolean) overschrijven Dispose(Boolean) en aanroepen.
  • Ze kunnen indien nodig een finalizer bieden. De finalizer moet aanroepen Dispose(false).

Houd er rekening mee dat afgeleide klassen zelf de IDisposable interface niet implementeren en geen parameterloze Dispose methode bevatten. Ze overschrijven alleen de basisklassemethode Dispose(Boolean) .

Het volgende codefragment weerspiegelt het verwijderingspatroon voor afgeleide klassen. Hierbij wordt ervan uitgegaan dat uw type de Object.Finalize methode niet overschrijft.

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