Objecten weggooien

In het artikel Coding New Instances of Objects schreef ik over de verschillende manieren waarop Nieuw instanties van objecten kunnen worden gemaakt. Het tegenovergestelde probleem, het weggooien van een object, is iets waar u zich in VB.NET niet vaak zorgen over hoeft te maken ... NET bevat een technologie genaamd Vuilnisman (GC) die meestal voor alles achter de schermen stil en efficiënt zorgt. Maar soms, meestal bij het gebruik van bestandsstreams, sql-objecten of grafische (GDI +) objecten (dat wil zeggen, onbeheerde bronnen), moet u mogelijk de controle over het verwijderen van objecten in uw eigen code overnemen.

Eerst wat achtergrond

Net als een constructor (de Nieuw trefwoord) maakt een nieuw object, a destructor is een methode die wordt aangeroepen wanneer een object wordt vernietigd. Maar er is een addertje onder het gras. De mensen die .NET hebben gemaakt, beseften dat het een formule voor bugs was als twee verschillende stukjes code een object daadwerkelijk konden vernietigen. Dus .NET GC heeft eigenlijk de controle en is meestal de enige code die de instantie van het object kan vernietigen. De GC vernietigt een object wanneer het beslist en niet eerder. Normaal gesproken is het nadat een object de scope heeft verlaten vrijgelaten door de Common Language Runtime (CLR). De GC vernietigt objecten wanneer de CLR meer vrij geheugen nodig heeft. Dus het komt erop neer dat je niet kunt voorspellen wanneer GC het object daadwerkelijk zal vernietigen.

(Welllll ... Dat is waar bijna de hele tijd. Je kan bellen GC.Collect en dwingen een afvalinzamelcyclus, maar autoriteiten zeggen universeel dat het een slecht idee en totaal overbodig.)

Als uw code bijvoorbeeld een heeft gemaakt Klant object, lijkt het erop dat deze code deze opnieuw zal vernietigen.

Klant = niets

Maar dat doet het niet. (Een object instellen op Niets wordt gewoonlijk genoemd, dereferentie het object.) Eigenlijk betekent dit alleen dat de variabele niet meer aan een object is gekoppeld. Enige tijd later zal de GC merken dat het object beschikbaar is voor vernietiging.

Trouwens, voor beheerde objecten is dit allemaal niet echt nodig. Hoewel een object zoals een knop een Dispose-methode biedt, is het niet nodig om het te gebruiken en weinig mensen doen dat. Windows Forms-componenten worden bijvoorbeeld toegevoegd aan een containerobject met de naam componenten. Wanneer u een formulier sluit, wordt de methode Verwijderen automatisch aangeroepen. Meestal hoeft u zich hier alleen maar zorgen over te maken wanneer u onbeheerde objecten gebruikt, en zelfs dan alleen om uw programma te optimaliseren.

De aanbevolen manier om bronnen vrij te geven die door een object kunnen worden vastgehouden, is door de Gooi methode voor het object (als er een beschikbaar is) en vervolgens het object derefereren.

 Customer.Dispose () Customer = Niets 

Omdat GC een zwevend object vernietigt, ongeacht of u de objectvariabele op Niets instelt, is het niet echt nodig.

Een andere aanbevolen manier om ervoor te zorgen dat objecten worden vernietigd wanneer ze niet meer nodig zijn, is door de code die een object gebruikt in een te plaatsen Gebruik makend van blok. Een gebruiksblok garandeert de verwijdering van een of meer van dergelijke bronnen wanneer uw code daarmee is voltooid.

In de GDI + -serie is de Gebruik makend van block wordt vrij vaak gebruikt om die vervelende grafische objecten te beheren. Bijvoorbeeld…

 MyBrush gebruiken als LinearGradientBrush _ = New LinearGradientBrush (_ Me.ClientRectangle, _ Color.Blue, Color.Red, _ LinearGradientMode.Horizontal) Eindgebruik 

myBrush wordt automatisch verwijderd wanneer het einde van het blok wordt uitgevoerd.

De GC-benadering van geheugenbeheer is een grote verandering ten opzichte van de manier waarop VB6 het deed. COM-objecten (gebruikt door VB6) werden vernietigd toen een interne referentieteller nul bereikte. Maar het was te gemakkelijk om een ​​fout te maken, dus de interne teller stond uit. (Omdat geheugen vast zat en niet beschikbaar was voor andere objecten toen dit gebeurde, werd dit een "geheugenlek" genoemd.) In plaats daarvan controleert GC eigenlijk of iets naar een object verwijst en vernietigt het wanneer er geen referenties meer zijn. De GC-aanpak heeft een goede geschiedenis in talen zoals Java en is een van de grote verbeteringen in .NET.

Op de volgende pagina kijken we naar de IDisposable-interface ... de interface die moet worden gebruikt als u onbeheerde objecten in uw eigen code wilt verwijderen.

Als u uw eigen object codeert dat onbeheerde bronnen gebruikt, moet u de IDisposable interface voor het object. Microsoft maakt dit gemakkelijk door een codefragment op te nemen dat het juiste patroon voor u maakt.

--------
Klik hier om de illustratie weer te geven
Klik op de knop Terug in uw browser om terug te keren
--------

De toegevoegde code ziet er zo uit (VB.NET 2008):

 Klasse ResourceClass implementeert IDisposable 'Om overbodige oproepen te detecteren Privé verwijderd als Boolean = False' IDisposable Beschermd Overridable Sub Dispose (_ ByVal als Boolean) If Not Me.disposed Dan If disposing Dan 'Free other state (managed objects). End If 'Free your own state (onbeheerde objecten). 'Zet grote velden op nul. End If Me.disposed = True End Sub #Region "IDisposable Support" 'Deze code is toegevoegd door Visual Basic om het wegwerppatroon correct te implementeren. Public Sub Dispose () Implementeert IDisposable.Dispose 'Wijzig deze code niet. 'Zet opruimcode in' Verwijder (ByVal weggooien als Boolean) hierboven. Dispose (True) GC.SuppressFinalize (Me) End Sub Protected Overrides Sub Finalize () 'Wijzig deze code niet. 'Zet opruimcode in' Verwijder (ByVal weggooien als Boolean) hierboven. Dispose (False) MyBase.Finalize () End Sub #End Region End Class 

Gooi is bijna een "afgedwongen" ontwikkelaarspatroon in .NET. Er is echt maar één juiste manier om dit te doen en dit is het. Je denkt misschien dat deze code iets magisch doet. Dat doet het niet.

Merk eerst op dat de interne vlag geneigd sluit de hele zaak kort, zodat u kunt bellen Dispose (afvoeren) zo vaak als je wilt.

De code…

 GC.SuppressFinalize (Me) 

... maakt uw code efficiënter door de GC te vertellen dat het object al is verwijderd (een 'dure' operatie in termen van uitvoeringscycli). Finaliseren wordt beschermd omdat GC het automatisch aanroept wanneer een object wordt vernietigd. Je moet nooit Finalize bellen. De Boolean afvoeren vertelt de code of uw code de verwijdering van het object heeft geïnitieerd (True) of dat de GC het heeft gedaan (als onderdeel van de Afronden sub. Merk op dat de enige code die de Boolean gebruikt afvoeren is:

 Als weggooien Dan 'Andere staat vrijmaken (beheerde objecten). Stop als 

Wanneer u een object weggooit, moeten alle middelen ervan worden verwijderd. Wanneer de CLR-vuilnisman over een object beschikt, moeten alleen de onbeheerde bronnen worden verwijderd, omdat de vuilnisman automatisch voor de beheerde bronnen zorgt.

Het idee achter dit codefragment is dat u code toevoegt om te zorgen voor beheerde en onbeheerde objecten op de aangegeven locaties.

Wanneer u een klasse ontleent aan een basisklasse die IDisposable implementeert, hoeft u geen van de basismethoden te overschrijven, tenzij u andere bronnen gebruikt die ook moeten worden verwijderd. Als dat gebeurt, moet de afgeleide klasse de methode Dispose (disposing) van de basisklasse overschrijven om de bronnen van de afgeleide klasse te verwijderen. Maar vergeet niet om de Dispose (disposing) methode van de basisklasse aan te roepen.

 Protected Overrides Sub Dispose (ByVal weggooien als Boolean) If Not Me.disposed When If disposing Then 'Voeg uw code toe om beheerde bronnen vrij te maken. End If 'Voeg uw code toe om onbeheerde bronnen vrij te maken. Einde Als MyBase.Dispose (weggooien) Einde Sub 

Het onderwerp kan enigszins overweldigend zijn. Het doel van de uitleg hier is om te "demystificeren" wat er feitelijk gebeurt omdat de meeste informatie die u kunt vinden u niet vertelt!