Objektlivslängd: Hur objekt skapas och förstörs (Visual Basic)
En instans av en klass, ett objekt, skapas med hjälp av nyckelordet New
. Initieringsuppgifter måste ofta utföras på nya objekt innan de används. Vanliga initieringsuppgifter är att öppna filer, ansluta till databaser och läsa värden för registernycklar. Visual Basic styr initieringen av nya objekt med hjälp av procedurer som kallas konstruktorer (särskilda metoder som tillåter kontroll över initiering).
När ett objekt lämnar omfånget släpps det av CLR (Common Language Runtime). Visual Basic styr versionen av systemresurser med hjälp av procedurer som kallas destructors. Tillsammans stöder konstruktorer och destruatorer skapandet av robusta och förutsägbara klassbibliotek.
Använda konstruktorer och destruktörer
Konstruktorer och destruktorer styr skapandet och förstörelsen av objekt. Procedurerna Sub New
och Sub Finalize
i Visual Basic initierar och förstör objekt. De ersätter metoderna Class_Initialize
och Class_Terminate
som används i Visual Basic 6.0 och tidigare versioner.
Under ny
Konstruktorn Sub New
kan bara köras en gång när en klass skapas. Den kan inte anropas explicit någon annanstans än i den första kodraden för en annan konstruktor från antingen samma klass eller från en härledd klass. Dessutom körs koden i Sub New
metoden alltid före någon annan kod i en klass. Visual Basic skapar implicit en Sub New
konstruktor vid körning om du inte uttryckligen definierar en Sub New
procedur för en klass.
Skapa en konstruktor för en klass genom att skapa en procedur med namnet Sub New
var som helst i klassdefinitionen. Om du vill skapa en parameteriserad konstruktor anger du namn och datatyper av argument på Sub New
samma sätt som du anger argument för andra procedurer, som i följande kod:
Sub New(ByVal s As String)
Konstruktorer överbelastas ofta, som i följande kod:
Sub New(ByVal s As String, i As Integer)
När du definierar en klass som härletts från en annan klass måste den första raden i en konstruktor vara ett anrop till konstruktorn för basklassen, såvida inte basklassen har en tillgänglig konstruktor som inte tar några parametrar. Ett anrop till basklassen som innehåller konstruktorn ovan är MyBase.New(s)
till exempel . Annars MyBase.New
är det valfritt och Visual Basic-körningen anropar det implicit.
När du har skrivit koden för att anropa det överordnade objektets konstruktor kan du lägga till ytterligare initieringskod i proceduren Sub New
. Sub New
kan acceptera argument när de anropas som en parameteriserad konstruktor. Dessa parametrar skickas från proceduren som anropar konstruktorn, Dim AnObject As New ThisClass(X)
till exempel .
Underslut
Innan objekt frigörs anropar Finalize
CLR automatiskt metoden för objekt som definierar en Sub Finalize
procedur. Metoden Finalize
kan innehålla kod som måste köras precis innan ett objekt förstörs, till exempel kod för att stänga filer och spara tillståndsinformation. Det finns en liten prestandaförseelse för att Sub Finalize
köra , så du bör definiera en Sub Finalize
metod endast när du behöver släppa objekt explicit.
Kommentar
Skräpinsamlaren i CLR tar inte bort (och kan inte) ta bort ohanterade objekt, objekt som operativsystemet kör direkt utanför CLR-miljön. Det beror på att olika ohanterade objekt måste tas bort på olika sätt. Den informationen är inte direkt kopplad till det ohanterade objektet. det måste hittas i dokumentationen för objektet. En klass som använder ohanterade objekt måste ta bort dem i sin Finalize
metod.
Destructor Finalize
är en skyddad metod som endast kan anropas från den klass som den tillhör eller från härledda klasser. Systemet anropar Finalize
automatiskt när ett objekt förstörs, så du bör inte uttryckligen anropa Finalize
utanför implementeringen av en härledd klass Finalize
.
Till skillnad från Class_Terminate
, som körs så snart ett objekt har angetts till ingenting, uppstår det vanligtvis en fördröjning mellan när ett objekt förlorar omfånget och när Visual Basic anropar Finalize
destrukteraren. Visual Basic .NET möjliggör en andra typ av destructor, IDisposable.Dispose, som uttryckligen kan anropas när som helst för att omedelbart frigöra resurser.
Kommentar
En Finalize
destructor bör inte utlösa undantag, eftersom de inte kan hanteras av programmet och kan få programmet att avslutas.
Hur nya och slutför metoder fungerar i en klasshierarki
När en instans av en klass skapas försöker CLR (Common Language Runtime) köra en procedur med namnet New
, om den finns i objektet. New
är en typ av procedur som kallas en constructor
som används för att initiera nya objekt innan någon annan kod i ett objekt körs. En New
konstruktor kan användas för att öppna filer, ansluta till databaser, initiera variabler och ta hand om andra uppgifter som behöver utföras innan ett objekt kan användas.
När en instans av en härledd klass skapas Sub New
körs konstruktorn för basklassen först, följt av konstruktorer i härledda klasser. Detta beror på att den första kodraden i en Sub New
konstruktor använder syntaxen MyBase.New()
för att anropa konstruktorn för klassen omedelbart ovanför sig själv i klasshierarkin. Konstruktorn Sub New
anropas sedan för varje klass i klasshierarkin tills konstruktorn för basklassen har nåtts. Då körs koden i konstruktorn för basklassen, följt av koden i varje konstruktor i alla härledda klasser och koden i de mest härledda klasserna körs sist.
När ett objekt inte längre behövs anropar Finalize CLR -metoden för objektet innan dess minne frigörs. Metoden Finalize kallas för en destructor
eftersom den utför rensningsuppgifter, till exempel att spara tillståndsinformation, stänga filer och anslutningar till databaser och andra uppgifter som måste utföras innan objektet släpps.
IDisposable-gränssnitt
Klassinstanser styr ofta resurser som inte hanteras av CLR, till exempel Windows-handtag och databasanslutningar. Dessa resurser måste tas bort i -metoden för Finalize
klassen, så att de släpps när objektet förstörs av skräpinsamlaren. Skräpinsamlaren förstör dock bara objekt när CLR kräver mer ledigt minne. Det innebär att resurserna kanske inte släpps förrän långt efter att objektet har gått utanför omfånget.
För att komplettera skräpinsamlingen kan klasserna tillhandahålla en mekanism för att aktivt hantera systemresurser om de implementerar IDisposable gränssnittet. IDisposable har en metod, Dispose, som klienter ska anropa när de är klara med ett objekt. Du kan använda Dispose metoden för att omedelbart frigöra resurser och utföra uppgifter som att stänga filer och databasanslutningar. Till skillnad från destructor Finalize
anropas Dispose inte metoden automatiskt. Klienter i en klass måste uttryckligen anropa Dispose när du omedelbart vill frigöra resurser.
Implementera IDisposable
En klass som implementerar IDisposable gränssnittet bör innehålla följande kodavsnitt:
Ett fält för att hålla reda på om objektet har tagits bort:
Protected disposed As Boolean = False
En överlagring av Dispose som frigör klassens resurser. Den här metoden ska anropas av Dispose metoderna och
Finalize
för basklassen: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
En implementering av Dispose som endast innehåller följande kod:
Public Sub Dispose() Implements IDisposable.Dispose Dispose(True) GC.SuppressFinalize(Me) End Sub
En åsidosättning av metoden
Finalize
som endast innehåller följande kod:Protected Overrides Sub Finalize() Dispose(False) MyBase.Finalize() End Sub
Härled från en klass som implementerar IDisposable
En klass som härleds från en basklass som implementerar IDisposable gränssnittet behöver inte åsidosätta någon av basmetoderna om den inte använder ytterligare resurser som behöver tas bort. I så fall bör den härledda klassen åsidosätta basklassens Dispose(disposing)
metod för att ta bort den härledda klassens resurser. Den här åsidosättningen måste anropa basklassens Dispose(disposing)
metod.
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
En härledd klass bör inte åsidosätta basklassens Dispose och Finalize
metoderna. När dessa metoder anropas från en instans av den härledda klassen anropar basklassens implementering av dessa metoder den härledda klassens åsidosättning av Dispose(disposing)
metoden.
Skräpinsamling och slutför destructor
.NET Framework använder skräpinsamlingssystemet för referensspårning för att regelbundet frigöra oanvända resurser. Visual Basic 6.0 och tidigare versioner använde ett annat system som kallas referensräkning för att hantera resurser. Även om båda systemen utför samma funktion automatiskt finns det några viktiga skillnader.
CLR förstör regelbundet objekt när systemet fastställer att sådana objekt inte längre behövs. Objekt frigörs snabbare när systemresurserna är en bristvara, och mindre ofta annars. Fördröjningen mellan när ett objekt förlorar omfånget och när CLR släpps innebär det att du, till skillnad från objekt i Visual Basic 6.0 och tidigare versioner, inte kan avgöra exakt när objektet kommer att förstöras. I en sådan situation sägs objekt ha icke-deterministisk livslängd. I de flesta fall ändrar inte icke-deterministisk livslängd hur du skriver program, så länge du kommer ihåg att Finalize
destruktor kanske inte omedelbart körs när ett objekt förlorar omfånget.
En annan skillnad mellan systemen för skräpinsamling är användningen av Nothing
. För att dra nytta av referensräkning i Visual Basic 6.0 och tidigare versioner tilldelas Nothing
programmerare ibland objektvariabler för att frigöra de referenser som dessa variabler innehåller. Om variabeln innehöll den sista referensen till objektet släpptes objektets resurser omedelbart. I senare versioner av Visual Basic, även om det kan finnas fall där den här proceduren fortfarande är värdefull, får det refererade objektet aldrig att frigöra sina resurser omedelbart. Om du vill frigöra resurser omedelbart använder du objektets -metod, om det är Dispose tillgängligt. Den enda tid du bör ange en variabel till Nothing
är när dess livslängd är lång i förhållande till den tid skräpinsamlaren tar för att identifiera överblivna objekt.