Zie Scherp Scherper - Hoofdstuk 10
Na dit hoofdstuk kan je:
uitleggen hoe het geheugen verdeeld is in stack en heap
het verschil tussen value types en reference types doorgronden
de rol van de Garbage Collector beschrijven
werken met null en de NullReferenceException vermijden
namespace en using situeren
robuuste code schrijven met try, catch en finally
Een C#-programma krijgt twee geheugens:
de kleine, snelle stack
het grote, tragere heap
| Value types | Reference types | |
|---|---|---|
| Inhoud | de waarde zelf | een verwijzing naar de data |
| Locatie | stack | heap |
| Default | 0, false, … |
null |
= kopieert |
de waarde | het adres |
De stack is bij het compileren al exact berekenbaar (snel, vaste grootte)
De heap is voor data waarvan de grootte pas tijdens de uitvoer bekend is (arrays, objecten)
De heap is de grote speelplaats; de stack het kleine, snelle bankje ernaast.
= kopieert de waarde. Een methode krijgt een kopie:
1. new Student() maakt het object in de heap en geeft het adres terug
2. de variabele stud staat in de stack
3. dat adres wordt in stud bewaard
Opmerking
Zonder new is stud nog null: een lege doos, zonder verwijzing.
Een object kan groot zijn, een echte “menhir” in het geheugen.
Een referentie is maar een klein adres dat ernaar wijst.
Tip
Obelix sleurt niet met elke menhir mee: hij verlegt gewoon het bordje dat ernaar wijst. Net zo werkt je computer met objecten.
Objecten in de heap waar geen referentie meer naar wijst, worden door de GC opgeruimd:
Waarschuwing
Roep nooit zelf GC.Collect() op. De GC kiest zelf het beste moment; jij maakt het meestal net trager.
string is een reference type, maar gedraagt zich vaak als een value type omdat het immutable is:
Tip
Methoden op een string geven steeds een nieuwe string terug. Vergeet je de toewijzing (naam.ToUpper();), dan verandert er niets.
Objecten gaan by reference naar een methode. Aanpassingen werken op het origineel:
Opmerking
Een methode mag ook een object teruggeven (return new Meting();), bijvoorbeeld PlantVoort() die een nieuw Mens-object oplevert.
Een methode kan een nieuw object teruggeven, met je eigen regels:
Tip
Jij bepaalt de regels van je objecten: een baby wordt nooit langer dan de grootste ouder, en enkel een Mens met de juiste eigenschappen kan KrijgKind aanroepen.
Waarschuwing
“Object reference not set to an instance of an object”: de beruchte NullReferenceException. Je gebruikt een object dat nog niet met new is gemaakt.
Het ?. (null-conditional) voert de code enkel uit als het object niet null is
Een methode mag bewust null teruggeven (bv. “niet gevonden”)
Opmerking
Groene kronkellijntjes rond null? Dat is de nullable reference types-functie. Die behandelen we bewust nog niet; je mag ze voorlopig negeren.
Een namespace voorkomt naamconflicten tussen klassen:
De volledige naam is MyEpicGame.Monster, dus een Monster uit een ander project (NietZoEpicGame.Monster) botst er niet mee.
De politie, uw vriend! Vraag je “waar is de Kerkstraat?”, dan vragen wij eerst: in welke gemeente?
Een namespace is net die gemeentenaam: ze laat toe een klasse (de straat) zonder verwarring te identificeren.
Zo zeg je:
“Zoek je een klasse en vind je ze niet, kijk dan ook in deze bibliotheek”
Het VS-lampje vindt een ontbrekende using voor je
Via NuGet voeg je extra bibliotheken toe (zoek eens Colorful.Console)
Uitzonderingen liggen vaak buiten je controle:
Data die er niet is
verplaatst bestand, wegvallende wifi
Foute invoer
van de gebruiker
Programmeerfouten
deling door nul, een null-object
Tip
Een onafgehandelde exception toont een joekel van een foutmelding en sluit je programma af. Exception handling laat je netjes reageren, zonder een woud aan if-checks.
Vroeger checkte je elke stap met if’s, diep genest:
Waarschuwing
Onleesbaar en foutgevoelig. try/catch scheidt de gewone flow netjes van de foutafhandeling.
In het try-blok staat code die kan mislukken
Het catch-blok vangt de uitzondering op en laat je programma netjes verder werken
Je kan zelf een uitzondering opwerpen:
Opmerking
Bij een throw klimt de uitvoering omhoog door de methode-aanroepen (stack unwinding) tot er een passend catch-blok klaarstaat. Daarom telt de plaats van je try/catch.
Exceptions vormen een hiërarchie: FormatException is óók een Exception.
Waarschuwing
Specifiek eerst, algemeen laatst. Zet je catch (Exception) bovenaan, dan compileert je code niet: het zou alles al opvangen.
Message, StackTrace, TargetSite, … geven info over de fout.
Belangrijk
Stuur deze info niet zomaar naar de gebruiker: ze kan gevoelige details bevatten die kwaadwillige gebruikers misbruiken.
Tip
Een leeg catch-blok is een anti-pattern: je verbergt bugs in plaats van ze op te lossen.
Rond de hele methode-aanroep
bij de eerste fout stopt alles
Rond één stap in een loop
een foute url wordt overgeslagen, de rest gaat door
Het geheugen splitst in een snelle stack (value types) en een flexibele heap (reference types)
= kopieert bij objecten het adres, niet het object: pas op voor de alias-val
De Garbage Collector ruimt onbereikbare objecten op; vergeet new niet (null!)
namespace en using ordenen je klassen en voorkomen naamconflicten
try/catch/finally vangt uitzonderingen op: specifiek eerst, algemeen laatst
Tip
Volgende halte: gevorderde klasseconcepten, met constructors en static.
Kennisclips
Hoe doen andere programmeertalen hetzelfde? En een korte zoek-de-fout, om zo kritisch mogelijk naar code te leren kijken.
Onderstaande C#-code wil de naam van een student tonen, maar crasht met een NullReferenceException. Wat loopt er mis?
Opmerking
new Student[3] maakt wel een array aan, maar die bevat drie reference types die elk de defaultwaarde null hebben. Er staat dus nog geen Student-object op studenten[0]. Op de tweede regel probeer je .Naam te zetten op een object dat null is, en dat geeft een NullReferenceException. Maak eerst het object aan met studenten[0] = new Student(); voor je de instantievariabele invult.
C# heeft een GC. In C++ beheer je geheugen zelf met new en delete:
Vergeet je delete, dan lek je geheugen (memory leak). De C#-GC neemt dat risico van je over.
Python kent ook exceptions, maar catch heet er except:
De taal C heeft geen exceptions: je checkt zelf na elke aanroep een foutcode:
Een handige samenvattende poster (Opgelet: gemaakt m.b.v. ChatGPT Image Gen 2).