Auf Englisch lesen

Freigeben über


System.IDisposable-Schnittstelle

Dieser Artikel enthält ergänzende Hinweise zur Referenzdokumentation für diese API.

Die primäre Verwendung der IDisposable Schnittstelle besteht darin, nicht verwaltete Ressourcen freizugeben. Der Garbage Collector gibt automatisch den Speicher frei, der einem verwalteten Objekt zugeordnet ist, wenn dieses Objekt nicht mehr verwendet wird. Es ist jedoch nicht möglich, vorherzusagen, wann die Garbage Collection eintritt. Darüber hinaus verfügt der Garbage Collector nicht über nicht verwaltete Ressourcen wie Fensterhandles oder öffnen von Dateien und Datenströmen.

Verwenden Sie die Dispose Methode dieser Schnittstelle, um nicht verwaltete Ressourcen in Verbindung mit dem Garbage Collector explizit freizugeben. Der Consumer eines Objekts kann diese Methode aufrufen, wenn das Objekt nicht mehr benötigt wird.

Warnung

Es handelt sich um eine bahnbrechende Änderung, um die IDisposable Schnittstelle zu einer vorhandenen Klasse hinzuzufügen. Da bereits vorhandene Consumer Ihres Typs nicht aufgerufen Disposewerden können, können Sie nicht sicher sein, dass nicht verwaltete Ressourcen, die von Ihrem Typ gehalten werden, freigegeben werden.

Da die IDisposable.Dispose Implementierung vom Consumer eines Typs aufgerufen wird, wenn die Ressourcen, die einer Instanz gehören, nicht mehr benötigt werden, sollten Sie entweder das verwaltete Objekt in eine SafeHandle (die empfohlene Alternative) einschließen, oder Sie sollten außer Kraft setzen Object.Finalize , um nicht verwaltete Ressourcen freizugeben, wenn der Verbraucher den Aufruf Disposevergessen hat.

Wichtig

In .NET Framework unterstützt der C++-Compiler die deterministische Entsorgung von Ressourcen und lässt keine direkte Implementierung der Dispose Methode zu.

Eine ausführliche Erläuterung dazu, wie diese Schnittstelle und die Object.Finalize Methode verwendet werden, finden Sie in den Themen " Garbage Collection " und "Implementieren einer Dispose-Methode ".

Verwenden eines Objekts, das IDisposable implementiert

Wenn Ihre App einfach ein Objekt verwendet, das die IDisposable Schnittstelle implementiert, sollten Sie die Implementierung des IDisposable.Dispose Objekts aufrufen, wenn Sie damit fertig sind. Je nach Programmiersprache können Sie dies auf eine von zwei Arten tun:

  • Mithilfe eines Sprachkonstrukts, z. B. der using Anweisung in C# und Visual Basic, und der use Anweisung oder using Funktion in F#
  • Durch umschließen des Aufrufs der IDisposable.Dispose Implementierung in einem try/finally Block.

Hinweis

Dokumentation für Typen, die beachten IDisposable , dass die Tatsache und eine Erinnerung zum Aufrufen der Dispose Implementierung enthalten.

Die C#-, F#- und Visual Basic Using-Anweisung

Wenn Ihre Sprache ein Konstrukt wie die using-Anweisung in C#, die Using-Anweisung in Visual Basic oder die Use-Anweisung in F# unterstützt, können Sie es verwenden, anstatt sie explizit selbst aufzurufen IDisposable.Dispose . Im folgenden Beispiel wird dieser Ansatz verwendet, um eine WordCount Klasse zu definieren, die Informationen zu einer Datei und die Anzahl der darin enthaltenen Wörter bewahrt.

C#
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; } }
}

Die using Anweisung (use Ausdruck in F#) ist tatsächlich eine syntaktische Bequemlichkeit. Zur Kompilierungszeit implementiert der Sprachcompiler die Zwischensprache (IL) für einen try/finally Block.

Weitere Informationen zur using Anweisung finden Sie in den Themen "Using Statement " oder "Using Statement" .

Der Try/Finally-Block

Wenn Ihre Programmiersprache kein Konstrukt wie die using Anweisung in C# oder Visual Basic oder die use Anweisung in F# unterstützt oder sie nicht verwenden möchte, können Sie die IDisposable.Dispose Implementierung aus dem finally Block einer try/finally Anweisung aufrufen. Im folgenden Beispiel wird der using Block im vorherigen Beispiel durch einen try/finally Block ersetzt.

C#
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; } }
}

Weitere Informationen zum try/finally Muster finden Sie unter Try... Fangen... Schließlich Anweisung, try-finally, try... schließlich Expression oder try-finally-Anweisung.

Implementieren von IDisposable

Sie sollten implementieren IDisposable , ob Ihr Typ nicht verwaltete Ressourcen direkt verwendet oder wenn Sie verfügbare Ressourcen selbst verwenden möchten. Die Verbraucher Ihres Typs können Ihre IDisposable.Dispose Implementierung aufrufen, um Ressourcen freizugeben, wenn die Instanz nicht mehr benötigt wird. Um Fälle zu behandeln, in denen sie nicht aufgerufen Disposewerden können, sollten Sie entweder eine von der klasse abgeleitete SafeHandle Klasse verwenden, um die nicht verwalteten Ressourcen umzuschließen, oder Sie sollten die Object.Finalize Methode für einen Verweistyp überschreiben. In beiden Fällen verwenden Sie die Dispose Methode, um alle erforderlichen sauber up auszuführen, nachdem die nicht verwalteten Ressourcen verwendet wurden, z. B. Freigeben, Freigeben oder Zurücksetzen der nicht verwalteten Ressourcen. Weitere Informationen zur Implementierung IDisposable.Disposefinden Sie unter der Dispose(bool)-Methodenüberladung.

Wichtig

Wenn Sie eine Basisklasse definieren, die nicht verwaltete Ressourcen verwendet und entweder über untergeordnete oder verworfene Unterklassen verfügt, sollten Sie die IDisposable.Dispose Methode implementieren und eine zweite Überladung bereitstellen Dispose, wie im nächsten Abschnitt beschrieben.

IDisposable und die Vererbungshierarchie

Eine Basisklasse mit Unterklassen, die verfügbar sein sollten, muss wie folgt implementiert IDisposable werden. Sie sollten dieses Muster immer dann verwenden, wenn Sie einen beliebigen Typ implementieren IDisposable , der nicht sealed (NotInheritable in Visual Basic) ist.

  • Sie sollte eine öffentliche, nicht virtuelle Dispose() Methode und eine geschützte virtuelle Dispose(Boolean disposing) Methode bereitstellen.
  • Die Dispose() Methode muss die Endisierung für die Leistung aufrufen Dispose(true) und unterdrücken.
  • Der Basistyp sollte keine Finalizer enthalten.

Das folgende Codefragment spiegelt das Dispose-Muster für Basisklassen wider. Es wird davon ausgegangen, dass der Typ die Object.Finalize Methode nicht überschreibt.

C#
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;
    }
}

Wenn Sie die Object.Finalize Methode außer Kraft setzen, sollte Ihre Klasse das folgende Muster implementieren.

C#
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);
    }
}

Unterklassen sollten das verwerfbare Muster wie folgt implementieren:

  • Sie müssen Dispose(Boolean) überschreiben und die Basisklassen-Dispose(Boolean)-Implementierung aufrufen.
  • Sie können bei Bedarf einen Finalizer bereitstellen. Der Finalizer muss Dispose(false) aufrufen.

Beachten Sie, dass abgeleitete Klassen die Schnittstelle nicht selbst implementieren IDisposable und keine parameterlose Dispose Methode enthalten. Sie überschreiben nur die Basisklassenmethode Dispose(Boolean) .

Das folgende Codefragment gibt das Dispose-Muster für abgeleitete Klassen wieder. Es wird davon ausgegangen, dass der Typ die Object.Finalize Methode nicht überschreibt.

C#
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);
    }
}