Freigeben über


Objektlebensdauer: Erstellen und Zerstören von Objekten (Visual Basic)

Eine Instanz einer Klasse, eines Objekts, wird mithilfe des New Schlüsselworts erstellt. Initialisierungsaufgaben müssen häufig für neue Objekte ausgeführt werden, bevor sie verwendet werden. Allgemeine Initialisierungsaufgaben umfassen das Öffnen von Dateien, das Herstellen einer Verbindung mit Datenbanken und das Lesen von Werten von Registrierungsschlüsseln. Visual Basic steuert die Initialisierung neuer Objekte mithilfe von Prozeduren, die als Konstruktoren bezeichnet werden (spezielle Methoden, die die Kontrolle über die Initialisierung ermöglichen).

Nachdem ein Objekt den Bereich verlässt, wird es von der Common Language Runtime (CLR) freigegeben. Visual Basic steuert die Veröffentlichung von Systemressourcen mithilfe von Prozeduren, die als Destruktoren bezeichnet werden. Zusammen unterstützen Konstruktoren und Destruktoren die Erstellung robuster und vorhersagbarer Klassenbibliotheken.

Verwenden von Konstruktoren und Destruktoren

Konstruktoren und Destruktoren steuern die Erstellung und Zerstörung von Objekten. Die Sub New und Sub Finalize Prozeduren in Visual Basic initialisieren und zerstören Objekte; sie ersetzen die in Visual Basic 6.0 und früheren Versionen verwendeten Class_Initialize und Class_Terminate Methoden.

Unter Neu

Der Sub New Konstruktor kann nur einmal ausgeführt werden, wenn eine Klasse erstellt wird. Sie kann nicht explizit an einer anderen Stelle als in der ersten Codezeile eines anderen Konstruktors aus derselben Klasse oder aus einer abgeleiteten Klasse aufgerufen werden. Darüber hinaus wird der Code in der Sub New Methode immer vor einem anderen Code in einer Klasse ausgeführt. Visual Basic erstellt implizit zur Laufzeit einen Sub New Konstruktor, wenn Sie keine Sub New Prozedur für eine Klasse explizit definieren.

Um einen Konstruktor für eine Klasse zu erstellen, erstellen Sie eine Prozedur, die an einer beliebigen Stelle in der Klassendefinition benannt ist Sub New . Um einen parametrisierten Konstruktor zu erstellen, geben Sie die Namen und Datentypen von Argumenten Sub New genauso an, wie Sie Argumente für eine andere Prozedur angeben würden, wie im folgenden Code:

Sub New(ByVal s As String)

Konstruktoren werden häufig überladen, wie im folgenden Code:

Sub New(ByVal s As String, i As Integer)

Wenn Sie eine von einer anderen Klasse abgeleitete Klasse definieren, muss die erste Zeile eines Konstruktors ein Aufruf des Konstruktors der Basisklasse sein, es sei denn, die Basisklasse verfügt über einen barrierefreien Konstruktor, der keine Parameter akzeptiert. Ein Aufruf der Basisklasse, die den obigen Konstruktor enthält, wäre beispielsweise MyBase.New(s). MyBase.New Andernfalls ist dies optional, und die Visual Basic-Laufzeit ruft sie implizit auf.

Nachdem Sie den Code zum Aufrufen des Konstruktors des übergeordneten Objekts geschrieben haben, können Sie der Sub New Prozedur zusätzlichen Initialisierungscode hinzufügen. Sub New kann Argumente akzeptieren, wenn sie als parametrisierter Konstruktor aufgerufen werden. Diese Parameter werden von der Prozedur übergeben, die den Konstruktor aufruft, wie zum Beispiel Dim AnObject As New ThisClass(X).

Sub Finalize

Vor dem Freigeben von Objekten ruft die CLR automatisch die Finalize Methode für Objekte auf, die eine Sub Finalize Prozedur definieren. Die Finalize Methode kann Code enthalten, der unmittelbar vor dem Löschen eines Objekts ausgeführt werden muss, z. B. Code zum Schließen von Dateien und Speichern von Statusinformationen. Es gibt eine geringfügige Leistungseinbuße für die Ausführung Sub Finalize. Daher sollten Sie eine Sub Finalize Methode nur dann definieren, wenn Sie Objekte explizit freigeben müssen.

Hinweis

Der Garbage Collector in der CLR entsorgt nicht (und kann nicht entsorgen) nicht verwaltete Objekte, Objekte, die vom Betriebssystem direkt außerhalb der CLR-Umgebung ausgeführt werden. Dies liegt daran, dass verschiedene nicht verwaltete Objekte auf unterschiedliche Weise verworfen werden müssen. Diese Informationen sind nicht direkt mit dem nicht verwalteten Objekt verknüpft; sie muss in der Dokumentation für das Objekt gefunden werden. Eine Klasse, die nicht verwaltete Objekte verwendet, muss sie in ihrer Finalize Methode löschen.

Der Finalize Destruktor ist eine geschützte Methode, die nur von der Klasse aufgerufen werden kann, zu der sie gehört, oder von abgeleiteten Klassen. Das System ruft automatisch aufFinalize, wenn ein Objekt zerstört wird. Daher sollten Sie nicht explizit von außerhalb der Implementierung einer abgeleiteten Klasse Finalize aufrufenFinalize.

Im Gegensatz dazu Class_Terminate, was ausgeführt wird, sobald ein Objekt auf nichts festgelegt ist, besteht in der Regel eine Verzögerung zwischen dem Verlust des Bereichs eines Objekts und dem Aufruf des Finalize Destruktors in Visual Basic. Visual Basic .NET ermöglicht eine zweite Art von Destruktor, IDisposable.Disposedie jederzeit explizit aufgerufen werden kann, um Ressourcen sofort freizugeben.

Hinweis

Ein Finalize Destruktor sollte keine Ausnahmen auslösen, da sie von der Anwendung nicht behandelt werden können und zum Absturz der Anwendung führen können.

Wie Neue und Finalize-Methoden in einer Klassenhierarchie arbeiten

Immer wenn eine Instanz einer Klasse erstellt wird, versucht die Common Language Runtime (CLR), eine Prozedur mit dem Namen Newauszuführen, sofern sie in diesem Objekt vorhanden ist. New ist ein Prozedurtyp namens constructor, der genutzt wird, um neue Objekte zu initialisieren, bevor irgendein anderer Code in einem Objekt ausgeführt wird. Ein New Konstruktor kann verwendet werden, um Dateien zu öffnen, eine Verbindung mit Datenbanken herzustellen, Variablen zu initialisieren und alle anderen Aufgaben zu erledigen, die ausgeführt werden müssen, bevor ein Objekt verwendet werden kann.

Wenn eine Instanz einer abgeleiteten Klasse erstellt wird, wird der Sub New Konstruktor der Basisklasse zuerst ausgeführt, gefolgt von Konstruktoren in abgeleiteten Klassen. Dies geschieht, da die erste Codezeile in einem Sub New Konstruktor die Syntax MyBase.New()verwendet, um den Konstruktor der Klasse direkt über sich selbst in der Klassenhierarchie aufzurufen. Der Sub New Konstruktor wird dann für jede Klasse in der Klassenhierarchie aufgerufen, bis der Konstruktor für die Basisklasse erreicht ist. Zu diesem Zeitpunkt wird der Code im Konstruktor der Basisklasse ausgeführt, gefolgt vom Code in jedem Konstruktor aller abgeleiteten Klassen, und der Code in den am weitesten abgeleiteten Klassen wird zuletzt ausgeführt.

Screenshot mit Klassenhierarchiekonstruktoren und Vererbung.

Wenn ein Objekt nicht mehr benötigt wird, ruft die CLR die Finalize Methode für dieses Objekt auf, bevor der Arbeitsspeicher freigegeben wird. Die Finalize-Methode wird als destructor bezeichnet, da sie Bereinigungsaufgaben ausführt, wie das Speichern von Statusinformationen, das Schließen von Dateien und das Trennen von Verbindungen zu Datenbanken sowie andere Aufgaben, die vor dem Freigeben des Objekts ausgeführt werden müssen.

Screenshot mit dem Finalize-Methodendestruktor.

IDisposable-Schnittstelle

Klasseninstanzen steuern häufig Ressourcen, die nicht von der CLR verwaltet werden, z. B. Windows-Handles und Datenbankverbindungen. Diese Ressourcen müssen in der Finalize-Methode der Klasse beseitigt werden, sodass sie freigegeben werden, wenn das Objekt vom Garbage Collector zerstört wird. Der Garbage Collector zerstört objekte jedoch nur, wenn der CLR mehr freien Arbeitsspeicher benötigt. Dies bedeutet, dass die Ressourcen möglicherweise erst freigegeben werden, lange nachdem das Objekt außerhalb des Gültigkeitsbereichs ist.

Zur Ergänzung der Garbagecollection können die Klassen einen Mechanismus für die aktive Verwaltung von Systemressourcen bereitstellen, wenn sie die IDisposable-Schnittstelle implementieren. IDisposable verfügt über eine Methode, die Clients aufrufen sollten, Disposewenn sie mit einem Objekt fertig sind. Mit der Dispose Methode können Sie Ressourcen sofort freigeben und Aufgaben wie das Schließen von Dateien und Datenbankverbindungen ausführen. Im Gegensatz zum Finalize-Destruktor wird die Dispose-Methode nicht automatisch aufgerufen. Clients einer Klasse müssen Dispose explizit aufrufen, wenn Ressourcen sofort freigegeben werden sollen.

Implementieren von IDisposable

Eine Klasse, die die IDisposable Schnittstelle implementiert, sollte diese Codeabschnitte enthalten:

  • Ein Feld zum Nachverfolgen, ob das Objekt entsorgt wurde.

    Protected disposed As Boolean = False
    
  • Eine Überladung von der Dispose, die die Ressourcen der Klasse freigibt. Diese Methode sollte von den Dispose und Finalize Methoden der Basisklasse aufgerufen werden.

    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposed Then
            If disposing Then
                ' Insert code to free managed resources.
            End If
            ' Insert code to free unmanaged resources.
        End If
        Me.disposed = True
    End Sub
    
  • Eine Implementierung von Dispose, die nur den folgenden Code enthält:

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
    
  • Eine Überschreibung der Finalize-Methode, die nur den folgenden Code enthält:

    Protected Overrides Sub Finalize()
        Dispose(False)
        MyBase.Finalize()
    End Sub
    

Ableiten von einer Klasse, die IDisposable implementiert

Eine Klasse, die von einer Basisklasse abgeleitet wird, die die IDisposable Schnittstelle implementiert, muss keine der Basismethoden außer Kraft setzen, es sei denn, sie verwendet zusätzliche Ressourcen, die verworfen werden müssen. In diesem Fall sollte die abgeleitete Klasse die Methode der Basisklasse Dispose(disposing) überschreiben, um die Ressourcen der abgeleiteten Klasse zu löschen. Diese Überschreibung muss die Methode der Basisklasse Dispose(disposing) aufrufen.

Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    If Not Me.disposed Then
        If disposing Then
            ' Insert code to free managed resources.
        End If
        ' Insert code to free unmanaged resources.
    End If
    MyBase.Dispose(disposing)
End Sub

Eine abgeleitete Klasse sollte die Methoden Dispose und Finalize der Basisklasse nicht überschreiben. Wenn diese Methoden aus einer Instanz der abgeleiteten Klasse aufgerufen werden, ruft die Basisklassenimplementierung dieser Methoden die Überschreibung der Dispose(disposing)-Methode auf.

Garbagecollection und der Finalize-Destruktor

.NET Framework verwendet das verweisverfolgenden Garbage Collection-System, um nicht verwendete Ressourcen in regelmäßigen Abständen freizugeben. Visual Basic 6.0 und frühere Versionen verwendeten ein anderes System, das als Verweiszählung bezeichnet wird, um Ressourcen zu verwalten. Obwohl beide Systeme die gleiche Funktion automatisch ausführen, gibt es einige wichtige Unterschiede.

Die CLR zerstört in regelmäßigen Abständen Objekte, wenn das System feststellt, dass solche Objekte nicht mehr benötigt werden. Objekte werden schneller freigegeben, wenn die Systemressourcen knapp sind, und ansonsten seltener. Die Verzögerung zwischen dem Verlust des Gültigkeitsbereichs eines Objekts und der Veröffentlichung der CLR bedeutet, dass Sie im Gegensatz zu Objekten in Visual Basic 6.0 und früheren Versionen nicht genau bestimmen können, wann das Objekt zerstört wird. In einer solchen Situation sollen Objekte nicht deterministische Lebenszeit haben. In den meisten Fällen ändert die nicht-deterministische Lebensdauer nicht, wie Sie Anwendungen schreiben, solange Sie daran denken, dass der Destruktor möglicherweise nicht sofort ausgeführt wird, wenn ein Objekt den Finalize Gültigkeitsbereich verliert.

Ein weiterer Unterschied zwischen den Müllsammelsystemen betrifft die Verwendung von Nothing. Um die Referenzzählung in Visual Basic 6.0 und früheren Versionen zu nutzen, wiesen Programmierer manchmal Nothing Objektvariablen zu, um die Verweise freizugeben, die diese Variablen hielten. Wenn die Variable den letzten Verweis auf das Objekt gehalten hat, wurden die Ressourcen des Objekts sofort freigegeben. In späteren Versionen von Visual Basic kann es fälle geben, in denen dieses Verfahren weiterhin nützlich ist, dies führt jedoch nie dazu, dass das referenzierte Objekt seine Ressourcen sofort freigibt. Um Ressourcen sofort freizugeben, verwenden Sie die Methode des Dispose Objekts, falls verfügbar. Die einzige Gelegenheit, eine Variable auf Nothing zu setzen, ist, wenn ihre Lebensdauer im Verhältnis zu der Zeit, die der Garbage Collector benötigt, um verwaiste Objekte zu erkennen, lang ist.

Siehe auch