Levensduur van objecten: hoe objecten worden gemaakt en vernietigd (Visual Basic)
Een exemplaar van een klasse, een object, wordt gemaakt met behulp van het New
trefwoord. Initialisatietaken moeten vaak worden uitgevoerd op nieuwe objecten voordat ze worden gebruikt. Algemene initialisatietaken omvatten het openen van bestanden, het maken van verbinding met databases en het lezen van waarden van registersleutels. Visual Basic bepaalt de initialisatie van nieuwe objecten met behulp van procedures die constructors worden genoemd (speciale methoden die controle over initialisatie mogelijk maken).
Nadat een object het bereik verlaat, wordt het vrijgegeven door de Common Language Runtime (CLR). Visual Basic bepaalt de release van systeembronnen met behulp van procedures die destructors worden genoemd. Samen ondersteunen constructors en destructors het maken van robuuste en voorspelbare klassebibliotheken.
Constructors en destructors gebruiken
Constructors en destructors bepalen het creëren en vernietigen van objecten. De Sub New
en Sub Finalize
procedures in Visual Basic initialiseren en vernietigen objecten; ze vervangen de Class_Initialize
methoden en Class_Terminate
methoden die worden gebruikt in Visual Basic 6.0 en eerdere versies.
Sub nieuw
De Sub New
constructor kan slechts eenmaal worden uitgevoerd wanneer een klasse wordt gemaakt. Het kan niet expliciet anders worden aangeroepen dan in de eerste regel code van een andere constructor van dezelfde klasse of van een afgeleide klasse. Bovendien wordt de code in de Sub New
methode altijd uitgevoerd vóór andere code in een klasse. Visual Basic maakt impliciet een Sub New
constructor tijdens runtime als u niet expliciet een Sub New
procedure voor een klasse definieert.
Als u een constructor voor een klasse wilt maken, maakt u een procedure met de naam Sub New
overal in de klassedefinitie. Als u een geparameteriseerde constructor wilt maken, geeft u de namen en gegevenstypen van argumenten op op Sub New
dezelfde manier als voor elke andere procedure, zoals in de volgende code:
Sub New(ByVal s As String)
Constructors worden vaak overbelast, zoals in de volgende code:
Sub New(ByVal s As String, i As Integer)
Wanneer u een klasse definieert die is afgeleid van een andere klasse, moet de eerste regel van een constructor een aanroep naar de constructor van de basisklasse zijn, tenzij de basisklasse een toegankelijke constructor heeft die geen parameters accepteert. Een aanroep naar de basisklasse die de bovenstaande constructor bevat, zou bijvoorbeeld zijn MyBase.New(s)
. Anders is MyBase.New
dit optioneel en roept de Visual Basic-runtime deze impliciet aan.
Nadat u de code hebt geschreven om de constructor van het bovenliggende object aan te roepen, kunt u aanvullende initialisatiecode toevoegen aan de Sub New
procedure. Sub New
kan argumenten accepteren wanneer deze worden aangeroepen als een geparameteriseerde constructor. Deze parameters worden doorgegeven vanuit de procedure die de constructor aanroept, bijvoorbeeld Dim AnObject As New ThisClass(X)
.
Subaftotaal voltooien
Voordat u objecten vrijgeeft, roept de CLR automatisch de Finalize
methode aan voor objecten die een Sub Finalize
procedure definiëren. De Finalize
methode kan code bevatten die moet worden uitgevoerd vlak voordat een object wordt vernietigd, zoals code voor het sluiten van bestanden en het opslaan van statusgegevens. Er is een lichte prestatiestraf voor het Sub Finalize
uitvoeren, dus u moet alleen een Sub Finalize
methode definiëren wanneer u objecten expliciet moet vrijgeven.
Notitie
De garbagecollector in de CLR verwijdert niet (en kan niet) onbeheerde objecten verwijderen , objecten die het besturingssysteem rechtstreeks uitvoert, buiten de CLR-omgeving. Dit komt doordat verschillende onbeheerde objecten op verschillende manieren moeten worden verwijderd. Deze informatie is niet rechtstreeks gekoppeld aan het onbeheerde object; deze moet worden gevonden in de documentatie voor het object. Een klasse die onbeheerde objecten gebruikt, moet deze in de Finalize
bijbehorende methode verwijderen.
De Finalize
destructor is een beveiligde methode die alleen kan worden aangeroepen vanuit de klasse waartoe deze behoort, of van afgeleide klassen. Het systeem roept Finalize
automatisch aan wanneer een object wordt vernietigd, dus u moet niet expliciet aanroepen Finalize
van buiten de implementatie van een afgeleide klasse Finalize
.
In tegenstelling tot Class_Terminate
, dat wordt uitgevoerd zodra een object op niets is ingesteld, is er meestal een vertraging tussen wanneer een object het bereik verliest en wanneer Visual Basic destructor Finalize
aanroept. Visual Basic .NET biedt een tweede soort destructor, IDisposable.Disposedie op elk gewenst moment expliciet kan worden aangeroepen om resources onmiddellijk vrij te geven.
Notitie
Een Finalize
destructor mag geen uitzonderingen genereren, omdat deze niet door de toepassing kunnen worden verwerkt en de toepassing kan worden beëindigd.
Hoe nieuwe methoden werken en voltooien in een klassehiërarchie
Wanneer een exemplaar van een klasse wordt gemaakt, probeert de Common Language Runtime (CLR) een procedure met de naam New
uit te voeren, als deze bestaat in dat object. New
is een type procedure dat wordt constructor
gebruikt om nieuwe objecten te initialiseren voordat andere code in een object wordt uitgevoerd. Een New
constructor kan worden gebruikt om bestanden te openen, verbinding te maken met databases, variabelen te initialiseren en andere taken uit te voeren die moeten worden uitgevoerd voordat een object kan worden gebruikt.
Wanneer een exemplaar van een afgeleide klasse wordt gemaakt, wordt de Sub New
constructor van de basisklasse eerst uitgevoerd, gevolgd door constructors in afgeleide klassen. Dit gebeurt omdat de eerste regel code in een Sub New
constructor de syntaxis MyBase.New()
gebruikt om de constructor van de klasse direct boven zichzelf in de klassehiërarchie aan te roepen. De Sub New
constructor wordt vervolgens aangeroepen voor elke klasse in de klassehiërarchie totdat de constructor voor de basisklasse is bereikt. Op dat moment wordt de code in de constructor voor de basisklasse uitgevoerd, gevolgd door de code in elke constructor in alle afgeleide klassen en wordt de code in de meest afgeleide klassen als laatste uitgevoerd.
Wanneer een object niet meer nodig is, roept de CLR de Finalize methode voor dat object aan voordat het geheugen wordt vrijgemaakt. De Finalize methode wordt een destructor
genoemd omdat er opschoontaken worden uitgevoerd, zoals het opslaan van statusgegevens, het sluiten van bestanden en verbindingen met databases en andere taken die moeten worden uitgevoerd voordat het object wordt vrijgegeven.
IDisposable Interface
Klasse-exemplaren beheren vaak resources die niet worden beheerd door de CLR, zoals Windows-ingangen en databaseverbindingen. Deze resources moeten worden verwijderd in de Finalize
methode van de klasse, zodat ze worden vrijgegeven wanneer het object wordt vernietigd door de garbagecollection. De garbagecollector vernietigt echter alleen objecten wanneer de CLR meer vrije geheugen nodig heeft. Dit betekent dat de resources mogelijk pas worden vrijgegeven nadat het object buiten het bereik valt.
Als aanvulling op garbagecollection kunnen uw klassen een mechanisme bieden om systeembronnen actief te beheren als ze de IDisposable interface implementeren. IDisposable heeft één methode, Disposedie clients moeten aanroepen wanneer ze klaar zijn met het gebruik van een object. U kunt de Dispose methode gebruiken om resources onmiddellijk vrij te geven en taken uit te voeren, zoals het sluiten van bestanden en databaseverbindingen. In tegenstelling tot de Finalize
destructor wordt de Dispose methode niet automatisch aangeroepen. Clients van een klasse moeten expliciet aanroepen Dispose wanneer u onmiddellijk resources wilt vrijgeven.
IDisposable implementeren
Een klasse die de IDisposable interface implementeert, moet de volgende codesecties bevatten:
Een veld om bij te houden of het object is verwijderd:
Protected disposed As Boolean = False
Een overbelasting van de Dispose resources van de klasse. Deze methode moet worden aangeroepen door de Dispose en
Finalize
methoden van de basisklasse: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
Een implementatie van Dispose die alleen de volgende code bevat:
Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub
Een onderdrukking van de
Finalize
methode die alleen de volgende code bevat:Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub
Afgeleid van een klasse die IDisposable implementeert
Een klasse die is afgeleid van een basisklasse die de IDisposable interface implementeert, hoeft geen van de basismethoden te overschrijven, tenzij er extra resources worden gebruikt die moeten worden verwijderd. In dat geval moet de afgeleide klasse de methode van Dispose(disposing)
de basisklasse overschrijven om de resources van de afgeleide klasse te verwijderen. Deze onderdrukking moet de methode van Dispose(disposing)
de basisklasse aanroepen.
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
Een afgeleide klasse mag de basisklasse Dispose en Finalize
methoden niet overschrijven. Wanneer deze methoden worden aangeroepen vanuit een exemplaar van de afgeleide klasse, roept de implementatie van de basisklasse van deze methoden de onderdrukking van de methode van de Dispose(disposing)
afgeleide klasse aan.
Garbagecollection en de destructor voltooien
Het .NET Framework maakt gebruik van het garbagecollectionsysteem referentietracering om periodiek ongebruikte resources vrij te geven. Visual Basic 6.0 en eerdere versies gebruikten een ander systeem, verwijzing tellen genoemd om resources te beheren. Hoewel beide systemen dezelfde functie automatisch uitvoeren, zijn er enkele belangrijke verschillen.
De CLR vernietigt periodiek objecten wanneer het systeem bepaalt dat dergelijke objecten niet meer nodig zijn. Objecten worden sneller vrijgegeven wanneer systeemresources in korte levering zijn en minder vaak anders. De vertraging tussen wanneer een object het bereik verliest en wanneer de CLR vrijgeeft, betekent dit dat, in tegenstelling tot objecten in Visual Basic 6.0 en eerdere versies, u niet precies kunt bepalen wanneer het object wordt vernietigd. In een dergelijke situatie wordt gezegd dat objecten een niet-deterministische levensduur hebben. In de meeste gevallen verandert de niet-deterministische levensduur niet hoe u toepassingen schrijft, zolang u zich herinnert dat de Finalize
destructor mogelijk niet onmiddellijk wordt uitgevoerd wanneer een object het bereik verliest.
Een ander verschil tussen de garbagecollection-systemen omvat het gebruik van Nothing
. Om te profiteren van het tellen van verwijzingen in Visual Basic 6.0 en eerdere versies, hebben programmeurs soms toegewezen Nothing
aan objectvariabelen om de verwijzingen die variabelen bevatten vrij te geven. Als de variabele de laatste verwijzing naar het object heeft, zijn de resources van het object onmiddellijk vrijgegeven. In latere versies van Visual Basic kunnen er gevallen zijn waarin deze procedure nog steeds waardevol is, waardoor het object waarnaar wordt verwezen nooit onmiddellijk de resources vrijgeeft. Als u resources onmiddellijk wilt vrijgeven, gebruikt u de methode van Dispose het object, indien beschikbaar. De enige tijd waarop u een variabele Nothing
moet instellen, is wanneer de levensduur ervan lang is ten opzichte van de tijd die de garbagecollector nodig heeft om zwevende objecten te detecteren.