Main roept zichzelf op, en die aanroep doet exact hetzelfde. Eindeloos “Ik zit vast!” tot het programma crasht. Waarom precies zie je straks bij de oneindige methode-lussen.
Tip
Via string[] args geef je opstartparameters mee aan je programma (denk aan explorer.exe google.com). Meer daarover in hoofdstuk 8.
Returntype en return
void betekent dat een methode niets teruggeeft. Vaak wil je wel iets terug:
Bij verschillende types helpt VS je wel: ToonInfo(37, "Tim") compileert gewoon niet.
Draai je de aanroep om, dan draait de deling mee om.
Opmerking
Zie je bij Console.WriteLine de versie met params object[] arg staan? params betekent: geef zoveel parameters mee als je wil. Zelf zoiets schrijven kan pas met arrays, in hoofdstuk 8.
By value
Parameters gaan standaard by value: de methode krijgt een kopie.
staticvoidJaartjeOuder(int leeftijd){ leeftijd++; Console.WriteLine($"Je bent {leeftijd} jaar geworden.");}
Je bent 40 jaar.Je bent 41 jaar geworden.Je bent 40 jaar. <- origineel ongewijzigd
De methode werkt op een kopie, dus mijnLeeftijd blijft 40.
Opmerking
By reference geeft het adres van de originele variabele mee, en komt aan bod vanaf het hoofdstuk over arrays. Je zag het al bij int.TryParse(Console.ReadLine(), out int leeftijd): die methode zet zelf een waarde in leeftijd.
Stagiair Steven
Steven laat de A.I. een methode schrijven die een getal verdubbelt:
“Ik roep Verdubbel op, dus punten is nu 10”, zegt hij zelfzeker. Wat verschijnt er op het scherm?
Opmerking
Er verschijnt Punten: 5. De methode werkt op een kopie, maar de echte fout is dat Steven het resultaat nergens opvangt. Verdubbel(punten); berekent wel 10, maar dat getal gaat verloren. Het moest punten = Verdubbel(punten); zijn. De code compileert zonder klacht, dus kreeg hij geen enkele waarschuwing.
Je krijgt een leeg scherm (“Klaar?” wordt nooit bereikt) en daarna een crash met een StackOverflowException.
Elke aanroep legt er een frame bij op de stack, en er komt er nooit een af.
Opmerking
Iedere aanroep neemt een stukje geheugen in op de zogenaamde stack, en die raakt vol. Wat die stack precies is, lees je in hoofdstuk 10.
Recursie (kort)
Recursie = een methode die zichzelf aanroept, maar wel stopt:
staticintBerekenSomRecursief(int start,int stop){int som = start;if(start < stop){ start++;return som +BerekenSomRecursief(start, stop);}return som;}
BerekenSomRecursief(1, 3) geeft 6.
Flow van de recursie.
Een geavanceerd concept; we komen het pas in hoofdstuk 18 kort terug tegen.
Lokale functies: niet doen
Sinds C# 7 mag een methode in een andere methode staan, maar als beginner doe je dat niet:
staticvoidMain(string[] args){TimVindtDitNietLeuk();staticvoidTimVindtDitNietLeuk()// NIET DOEN{ Console.WriteLine("Doe dit niet!");}}
Zo’n lokale functie kan je nergens anders aanroepen. Zet je methoden gewoon naastMain.
Belangrijk
Niet enkel een kwestie van smaak: op een vaardigheidsproef kost een methode in een methode je 3 punten.
Documentatie met ///
/// <summary>/// Berekent de macht van een getal./// </summary>/// <param name="grondtal">Het getal dat je verheft</param>/// <param name="exponent">De exponent</param>staticintMacht(int grondtal,int exponent){//...}
Typ /// boven een methode en VS maakt het skelet. Jij vult enkel de uitleg per parameter in.
Schrijf je documentatie best in het Engels, niet zoals in dit voorbeeld dus.
Wat kan die bibliotheek eigenlijk?
Typ Console. en wacht even: IntelliSense toont alles wat die bibliotheek kan.
Lijst per ongeluk weggeklikt? Ctrl+Spatie roept ze terug
Verschijnt er niets, dan heb je waarschijnlijk een schrijffout gemaakt
De parameters van een methode zien
Stop met typen na het eerste ronde haakje: IntelliSense toont alle manieren om de methode aan te roepen (de overloads), doorbladeren doe je met de pijltjes
Popup weg? Ctrl+Shift+Spatie
Cursor op de methode en F1 opent de online documentatie
Dit soort popups bevat een schat aan informatie.
Tip
Dit werkt ook voor je eigen methoden. Schreef je er ///-commentaar boven, dan staat jouw uitleg mee in die popup.
Named argument ‘student’ is used out-of-position but is followed by an unnamed argument. In beide foute lijnen staat student niet op de derde plaats, terwijl er daarna nog naamloze parameters volgen.
Optionele parameters
Geef een default waarde mee; die parameters staan achteraan:
Zonder naam landt de 6 in korting. Met btw: 6 blijft korting op zijn default.
Waarschuwing
ToonFactuur("Tim", 6) compileert zonder klacht, maar die 6 belandt in korting. Fouten met optionele parameters zijn zelden compilerfouten: je merkt ze pas aan de output. Schrijf ToonFactuur("Tim", btw: 6).
Method overloading
Dezelfde naam, maar een andere parameterlijst. De compiler kiest de juiste:
Het returntype mág verschillen, maar telt niet mee. Twee versies die enkel in returntype verschillen geven already defines a member called ‘Verdubbel’ with the same parameter types.
Overloaden op het aantal parameters
Naast ToonTitel(string naam) zetten we een versie zonder parameters, die gewoon de standaardtitel gebruikt:
Precies wat er bij Console.WriteLine() gebeurt: er bestaat een versie zonder parameters die een lege lijn toont.
Tip
Overload enkel wanneer je versies hetzelfde doen met andere input. Een BerekenOpp(lengte, breedte) naast een BerekenOpp(straal) compileert netjes, maar wie je code leest moet raden welke van de twee berekeningen bedoeld wordt.
Wanneer de compiler niet kan kiezen
staticvoidToonPrijs(int bedrag,double korting){}// versie AstaticvoidToonPrijs(double bedrag,int korting){}// versie B
Aanroep
Resultaat
ToonPrijs(100, 5.5)
versie A wordt uitgevoerd
ToonPrijs(99.9, 5)
versie B wordt uitgevoerd
ToonPrijs(100, 5)
fout: the call is ambiguous
ToonPrijs(99.9, 5.5)
fout: geen enkele versie past
Belangrijk
Bij ToonPrijs(100, 5) passen A en B even goed, en dan kiest de compiler niet. Jij maakt het duidelijk: ToonPrijs(100, 5.0) of ToonPrijs(100.0, 5). Hoe hij bij twijfel tussen types wél kiest (de betterness rule) is verdiepingsstof.
Methoden debuggen: step in
Herinner je de debugknoppen uit hoofdstuk 4? Eén lieten we toen liggen: step in.
Step over voert de methode wel uit, maar springt naar de volgende lijn van Main
Step in brengt je in je eigen methode, waar je lijn per lijn verder stapt
Simpel, maar oefen het toch een paar keer.
Step over versus step in.
Methoden in actie: verdeel en heers
Een groot probleem splits je op in kleine methoden, elk met een duidelijke taak: een IN (parameters), een ACTIE en een UIT (returntype).
Teken eerst een flowchart. Elk blokje wordt een methode. Daarna rijg je ze aan elkaar in een hoofdmethode.
Tip
Zo blijft je Main kort en lees je je programma als een inhoudstafel.
Showcase: Avenger Mission Planner
Nick Fury managet de Avengers. Elke fase van een missie is een methode:
Methode
IN
UIT
Alarm
niets
moeilijkheidsgraad (int, 0 = geen alarm)
MissieVoorbereiden
graad
naam held (string)
MissieUitvoeren
graad + held
missiepercentage (int)
Evaluatie
percentage + held
niets (void)
Avenger Mission Planner: de manager
Een MissieManager rijgt de losse methoden aan elkaar:
staticvoidMissieManager(int moeilijkheidsgraad){string held =MissieVoorbereiden(moeilijkheidsgraad);int percentage =MissieUitvoeren(moeilijkheidsgraad, held);Evaluatie(percentage, held);}
Tip
Uitbreiding: bij een alarm waarschuw je ook DC via DCWaarschuwer(moeilijkheidsgraad). Eén extra methode-aanroep, klaar.
Showcase: verhaal-generator
Bouw van onder naar boven, elke laag hergebruikt de vorige:
GenereerMedeklinkerhergebruiktIsKlinker: blijf letters trekken tot er een geen klinker is. Methoden die methoden gebruiken.
Verhaal-generator: zinnen samenstellen
staticstringGenereerKorteZin(){string onderwerp =GenereerNaam(6);string werkwoord =GenereerWerkwoord();// "gooit", "trapt", ...string voorwerp =GenereerVoorwerp();// "de bal", "de lepel", ...return $"{onderwerp} {werkwoord} {voorwerp}";}
Tip
Uitdaging: schrijf zelf GenereerVerhaal() dat meerdere zinnen met voegwoorden (” en “,”, maar “,”, dus “) aan elkaar plakt. Ben jij de volgende Shakespeare?
Showcase: Sinterklaas cadeau-generator
De Sint verdeelt het werk over drie hulp-elfen, elk een methode:
IsBraaf(...): braaf of stout? (bool)
BerekenAantalCadeaus(...): hoeveel cadeaus (int)
GenereerCadeau(): een willekeurig cadeau (string)
Een TestenMaar()-methode maakt met Random willekeurige kinderen en draait alles in een loop.
Tip
Zelfde idee als de Avengers: splits het probleem op, laat elke methode één ding goed doen.
Conclusie
Een methode is een herbruikbaar codeblok: minder fouten, betere leesbaarheid, en ze doet één ding
void geeft niets terug; anders gebruik je return met het juiste type, en vang je het resultaat ook op
Parameters gaan by value (een kopie); de volgorde telt
Named en optionele parameters en overloading maken je methoden flexibel
Met /// en IntelliSense werk je sneller en met betere documentatie
Tip
Volgende halte: arrays, om vele waarden samen in één variabele bij te houden.
Dezelfde concepten uit dit hoofdstuk, maar dan in andere talen. Handig om later code in Python of JavaScript te leren lezen.
Zie verder: methode-signatuur
Python doet dit zo:
def tel_op(a, b):return a + b
Geen returntype, geen types voor parameters. Dat scheelt typewerk, maar Python merkt een verkeerd type pas tijdens het uitvoeren.
Zie verder: bibliotheken importeren
In C# haal je bibliotheken binnen met using. Python doet dit met import:
import mathprint(math.sqrt(16))
Hetzelfde idee als bij C#: je geeft aan welke bibliotheek je wilt en spreekt de methoden aan via de naam (math.sqrt, zoals Math.Sqrt).
Zie verder: overloading
Python kent geen overloading: een tweede functie met dezelfde naam overschrijft de eerste. Meestal is dat niet nodig, want * werkt er op getallen én op strings: