- Let op Twee constructors met dezelfde toekenningen is dubbele code (boete Onnodige of redundante code). Laat de ene de andere oproepen met
: this(...)(uitleg). - Geef een constructorparameter een andere naam dan de instantievariabele, bv.
lengteIn.lengte = lengte;compileert, maar doet niets (waarschuwingCS1717). - Een klasse die toevalsgetallen nodig heeft, krijgt één
private static Random. Je geeft hem niet meer mee vanuitMain(uitleg). - Hoort iets bij alle objecten samen (een teller, een prijs voor iedereen), dan is het
static, en je spreekt het aan via de klassenaam:Pokemon.Info().
Meetlat constructor (Essential)
De kast voor je kot heb je gevonden met de Meetlat uit hoofdstuk 9. Eén ding stoorde: je kon een meetlat maken zonder lengte, en dan gaf ze overal 0. Met een constructor kan dat niet meer.
Stappenplan:
- Verwijder de write-only property
BeginLengte. - Voeg een constructor toe met één parameter van het type
double: de lengte in meter. Hij stopt die waarde in de private instantievariabelelengte, die er al staat. Noem de parameter nietlengtemaar bv.lengteIn. - De vier read-only properties (
LengteInM,LengteInCm,LengteInKmenLengteInVoet) blijven zoals ze zijn: ze lezenlengteal.
Testcode. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
Meetlat muur = new Meetlat(2.4);
Meetlat kast = new Meetlat(2.1);
Console.WriteLine($"Je muur is {muur.LengteInM} m hoog, of {muur.LengteInCm} cm.");
Console.WriteLine($"De kast is {kast.LengteInVoet:F2} voet hoog.");
if (kast.LengteInM < muur.LengteInM)
{
Console.WriteLine("De kast past onder het plafond.");
}
Meetlat fietstocht = new Meetlat(1850);
Console.WriteLine($"Van je kot naar de campus is {fietstocht.LengteInKm} km.");Je muur is 2,4 m hoog, of 240 cm.
De kast is 6,89 voet hoog.
De kast past onder het plafond.
Van je kot naar de campus is 1,85 km.
Voeg daarna Meetlat leeg = new Meetlat(); toe aan Main. Wat zegt de compiler, en waarom is dat hier net goed?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een constructor heeft de naam van de klasse en geen returntype. Hij loopt één keer: bij
new. - Een constructor met een parameter verplicht wie de klasse gebruikt om die waarde mee te geven. Zo bestaat er geen meetlat zonder lengte. Zie Welke constructors moet ik nu eigenlijk allemaal voorzien?.
Inschrijven voor de cantus (Essential) (GPT)
Deze oefening werd gemaakt (en aangepast nadien) met behulp van volgende GPT en heeft daarom de tag (GPT) achter de titel staan.
Je studentenclub organiseert een cantus, en jij schrijft het programma voor de inschrijvingen. Zonder voor- en achternaam kom je er niet in. Geboortejaar en e-mailadres zijn handig, maar niet verplicht.
Deel 1: de klasse.
- Klassenaam:
Persoon - Properties (auto):
Voornaam(string),Achternaam(string),Geboortejaar(int) enEmail(string). - Constructor met twee parameters: de voornaam en de achternaam.
- Is een van beide leeg (
""), dan werpt de constructor eenArgumentExceptionop met de boodschapVoornaam en achternaam mogen niet leeg zijn.EenArgumentExceptionis een exception die .NET al kent voor een parameter met een ongeldige waarde. Je werpt ze op zoals een gewone:throw new ArgumentException("...");. - Anders vult hij
VoornaamenAchternaamin.
- Is een van beide leeg (
- Methode
ToonInformatie(): toont{Voornaam} {Achternaam} geboren in {Geboortejaar} heeft emailadres: {Email}.
Geboortejaar en Email staan niet in de constructor. Die geef je mee met object initializer syntax: tussen accolades achter de haakjes van new. Dat werkt ook achter een constructor met parameters.
Testcode. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
try
{
Persoon jana = new Persoon("Jana", "Peeters") { Geboortejaar = 2007, Email = "jana.peeters@kotmail.be" };
jana.ToonInformatie();
Persoon anoniem = new Persoon("", "Janssens") { Geboortejaar = 2006 };
anoniem.ToonInformatie();
}
catch (ArgumentException e)
{
Console.WriteLine($"Inschrijving geweigerd: {e.Message}");
}Jana Peeters geboren in 2007 heeft emailadres: jana.peeters@kotmail.be
Inschrijving geweigerd: Voornaam en achternaam mogen niet leeg zijn.
Waarom verschijnt er geen tweede lijn met Janssens?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2: het lek. Zet deze lijnen onder de catch:
Persoon mo = new Persoon("Mo", "Janssens") { Achternaam = "" };
mo.ToonInformatie();Wat toont het programma? Hoe komt een lege achternaam langs je controle? Los het op zodat de achternaam en de voornaam na de constructor niet meer kunnen veranderen. Wat zegt de compiler daarna over deze twee lijnen?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een exception in de constructor houdt een fout object tegen: het wordt nooit afgewerkt. Zet de
tryrond de lijn metnew. - De initializer loopt pas ná de constructor. Een controle in de constructor helpt dus niet als de property daarna nog een public
setheeft. Zie Object initializer syntax. - Een property met een private
setkan je niet in een initializer zetten.
Koffie in de blokperiode
Het is blok, en de koffieautomaat in de bib draait overuren. Wie niets kiest, krijgt een espresso. Wie enkel een soort kiest, krijgt een medium met gewone melk.
Specificaties:
- Klassenaam:
Koffie - Properties:
Soort,Grootte(beidestring) enHaverMelk(bool): auto-properties met een privateset.Suikerklontjes(int): auto-property met een publicset.Prijs(double): read-only. Een"klein"kost 1,80 euro, een"medium"2,20 euro en een"groot"2,60 euro. Havermelk kost 0,40 euro extra. Suiker is gratis.
- Drie constructors:
Koffie(string soortIn, string grootteIn, bool haverMelkIn): vult de drie properties in. Dit is de enige constructor met toekenningen.Koffie(string soortIn): een medium zonder havermelk. Gebruik: this(...).Koffie(): een espresso. Ook met: this(...). Welke van de twee andere constructors roep je op?
- Methode
ToonBon(): toont bv.groot latte met havermelk (0 suiker): 3,00 euro. Zonder havermelk valtmet havermelkweg.
Testcode. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
Koffie eerste = new Koffie();
Koffie tweede = new Koffie("cappuccino");
Koffie derde = new Koffie("latte", "groot", true);
Koffie vierde = new Koffie("americano", "klein", false) { Suikerklontjes = 2 };
Koffie vijfde = new Koffie { Suikerklontjes = 1 };
eerste.ToonBon();
tweede.ToonBon();
derde.ToonBon();
vierde.ToonBon();
vijfde.ToonBon();medium espresso (0 suiker): 2,20 euro
medium cappuccino (0 suiker): 2,20 euro
groot latte met havermelk (0 suiker): 3,00 euro
klein americano (2 suiker): 1,80 euro
medium espresso (1 suiker): 2,20 euro
Kijk naar vijfde: er staan geen ronde haakjes achter new Koffie. Welke constructor wordt daar opgeroepen?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Met
: this(...)staan de toekenningen maar op één plaats. Moet er later iets bij (bv. een propertySuikersoort), dan pas je één constructor aan. Zie Constructors hergebruiken met this(). - Een initializer werkt achter elke constructor, met of zonder parameters. Gebruik je de default constructor, dan mogen de ronde haakjes weg.
Voorspel de uitvoer: een frietje na de les (Essential)
Na de laatste les haal je met je klasgenoten friet. Iemand schreef er een klasse voor, met een WriteLine in elke constructor en in een set, zodat je ziet wat er wanneer gebeurt:
internal class Friet
{
public Friet() : this("middel")
{
Console.WriteLine("A: default");
}
public Friet(string formaat) : this(formaat, "mayo")
{
Console.WriteLine($"B: {formaat}");
}
public Friet(string formaat, string saus)
{
Console.WriteLine($"C: {formaat} met {saus}");
}
private bool zout;
public bool Zout
{
get
{
return zout;
}
set
{
Console.WriteLine($"D: zout = {value}");
zout = value;
}
}
}In Main:
Console.WriteLine("Bestelling 1");
Friet eerste = new Friet();
Console.WriteLine("Bestelling 2");
Friet tweede = new Friet("groot") { Zout = true };
Console.WriteLine("Bestelling 3");
Friet derde = new Friet("klein", "stoofvleessaus");Schrijf eerst op papier wat het programma toont, lijn per lijn. Typ de code pas daarna over en vergelijk.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Bij
: this(...)loopt eerst de opgeroepen constructor, daarna de eigen body. Zie Constructors hergebruiken met this(). - De initializer komt na de constructor, ook achter een constructor met parameters. Zie Object initializer syntax.
Stevens constructors (Essential)
Stagiair Steven moest vier kleine klassen afwerken, telkens met een constructor erbij. Hij liet een A.I. het werk doen en leverde alles in zonder één keer op “Start” te klikken.
Lees elk stuk eerst zonder Visual Studio en antwoord op papier: compileert het? Zo nee, waar zit de fout en waarom? Zo ja, wat toont het programma? Typ de code pas daarna over en kijk of je gelijk had.
Deel 1. Een rugzak die weet hoeveel liter erin kan:
internal class Rugzak
{
private double inhoudInLiter;
public void Rugzak(double inhoud)
{
inhoudInLiter = inhoud;
}
public double InhoudInLiter
{
get { return inhoudInLiter; }
}
}In Main:
Rugzak schoolRugzak = new Rugzak(25);
Console.WriteLine($"Deze rugzak kan {schoolRugzak.InhoudInLiter} liter aan.");Compileert dit? Zo niet, wat moet er anders?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2. Een boek met een titel. Steven had zijn Main al geschreven voor de A.I. de constructor toevoegde:
internal class Boek
{
public Boek(string titelIn)
{
Titel = titelIn;
}
public string Titel { get; private set; }
public int AantalPaginas { get; set; }
}In Main:
Boek roman = new Boek("De Avonden");
roman.AantalPaginas = 316;
Boek notitieboek = new Boek();
notitieboek.AantalPaginas = 80;
Console.WriteLine($"{roman.Titel} telt {roman.AantalPaginas} pagina's.");
Console.WriteLine($"{notitieboek.Titel} telt {notitieboek.AantalPaginas} pagina's.");Compileert dit? Zo niet, los het op twee manieren op: één keer door enkel Main aan te passen, en één keer door enkel de klasse aan te passen.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 3. Een pizzeria wil weten hoeveel bestellingen er vandaag al waren, en per tafel hoeveel pizza’s die bestelde:
internal class Bestelling
{
private static int aantalBestellingen = 0;
private int aantalPizzas;
public Bestelling(int aantalPizzasIn)
{
aantalPizzas = aantalPizzasIn;
aantalBestellingen++;
}
public static void ToonOverzicht()
{
Console.WriteLine($"Vandaag al {aantalBestellingen} bestellingen.");
Console.WriteLine($"Deze bestelling telt {aantalPizzas} pizza's.");
}
}In Main:
Bestelling tafel1 = new Bestelling(3);
Bestelling tafel2 = new Bestelling(2);
Bestelling.ToonOverzicht();Compileert dit? Zo niet, welke regel is het probleem? Pas de klasse en Main aan zodat het programma eerst het aantal bestellingen toont en daarna het aantal pizza’s van elke tafel.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 4. Een spaarpot:
internal class Spaarpot
{
private double bedrag;
public Spaarpot(double bedrag)
{
bedrag = bedrag;
}
public double Bedrag
{
get { return bedrag; }
}
public void StopErIn(double extra)
{
bedrag = bedrag + extra;
}
}In Main:
Spaarpot pot = new Spaarpot(20);
pot.StopErIn(5);
Console.WriteLine($"In de spaarpot zit {pot.Bedrag} euro.");Steven verwacht In de spaarpot zit 25 euro. Compileert dit? Wat toont het programma echt, en waarom?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een constructor heeft geen returntype. Met
voidervoor is het een gewone methode. Zie Default constructors. - Schrijf je zelf een constructor, dan is de gratis default constructor weg. Heb je hem nodig, schrijf hem er dan bij en hergebruik de andere constructor met
this(...). Zie Overloaded constructors en Constructors hergebruiken met this(). - Een static methode heeft geen object en kan dus geen instantievariabelen lezen. Zie Static tegenover non-static.
- Deel 4 compileert, met één waarschuwing. Lees in de Error List ook de waarschuwingen, niet enkel de fouten.
Digitale kluis: code vergeten (Essential)

Je kotgenoot bewaart zijn laptop in een digitale kluis met een code van 0 tot en met 9999. Hij is de code vergeten. Voor je hem helpt kraken, bouw je zelf zo’n kluis na.
Deel 1: de kluis.
- Klassenaam:
DigitaleKluis - Instantievariabelen:
private int code(de echte code) enprivate int aantalPogingen(begint op 0). - Constructor met één
int: de code. Hij vult die in via de propertyCode. - Properties:
CanShowCode(bool): auto-property. Mag de code getoond worden?Code(int): full property met een privateset. Degetgeeft de echte code terug alsCanShowCodetrueis, en anders altijd-666.CodeLevel(int): read-only,code / 1000(gehele deling). Een code van 4500 heeft level 4.
- Methode
TryCode(int ingevoerdeCode): probeert een code, toont wat er gebeurt en geefttrueterug bij de juiste code, andersfalse. Elke poging telt, ook een juiste. Werk deze stappen in deze volgorde af:
| Stap | Situatie | Wat er gebeurt | Teruggeven |
|---|---|---|---|
| 1 | aantalPogingen is al 10 |
Toon Je hebt je 10 pogingen opgebruikt. Er wordt niets meer geteld. |
false |
| 2 | Anders | Verhoog aantalPogingen met 1, en kijk verder naar stap 3, 4 of 5. |
|
| 3 | ingevoerdeCode is -666 |
Toon CHEATER |
false |
| 4 | ingevoerdeCode is de code |
Toon Geldige code. Aantal pogingen = {aantalPogingen} |
true |
| 5 | Een andere code | Toon Geen geldige code. |
false |
Testcode deel 1. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
DigitaleKluis kluis = new DigitaleKluis(4500);
Console.WriteLine($"Code: {kluis.Code}, level {kluis.CodeLevel}");
kluis.CanShowCode = true;
Console.WriteLine($"Code: {kluis.Code}");
kluis.TryCode(-666);
kluis.TryCode(2000);
kluis.TryCode(4500);
for (int i = 0; i < 8; i++)
{
kluis.TryCode(1234);
}Code: -666, level 4
Code: 4500
CHEATER
Geen geldige code.
Geldige code. Aantal pogingen = 3
Geen geldige code.
Geen geldige code.
Geen geldige code.
Geen geldige code.
Geen geldige code.
Geen geldige code.
Geen geldige code.
Je hebt je 10 pogingen opgebruikt.
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2: kraken met brute force. Voeg aan de klasse een static methode toe die een kluis probeert te kraken door te gokken.
- Signatuur:
public static void BruteForce(DigitaleKluis kluis) - Werking: gok hoogstens 10 keer een willekeurige code van 0 tot en met 9999 en probeer ze met
kluis.TryCode(...). Lukt het, toon danGekraakt!en stop met gokken. - De klasse krijgt daarvoor één
private static Random. Waarom static?BruteForceis static en heeft geen eigen object: een gewone instantievariabele kan hij niet gebruiken.
Test in Main:
DigitaleKluis laptop = new DigitaleKluis(4500);
DigitaleKluis.BruteForce(laptop);Je ziet waarschijnlijk tien keer Geen geldige code. Waarom lukt het (bijna) nooit? Test daarna met een kluis met code 5, en verander in BruteForce tijdelijk de grenzen van je Next naar 0 tot en met 9. Zie je nu wel Gekraakt!?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 3: voor wie verder wil. code is private. Probeer in Main Console.WriteLine(laptop.code);. Probeer daarna in BruteForce kluis.TryCode(kluis.code). Wat zegt de compiler telkens? En had BruteForce met CanShowCode nog een andere achterdeur?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een static methode hoort bij de klasse en krijgt het object waarop ze werkt als parameter. Je roept ze op via de klassenaam:
DigitaleKluis.BruteForce(laptop). - Eén
private static Randomvoor de hele klasse. Zie static en Random. privatebeschermt tegen code buiten de klasse, niet tegen code in de klasse zelf.
Puntenrekenaar: hoeveel moet ik halen?
Je permanente evaluatie is binnen. Hoeveel moet je nu nog halen op het examen om te slagen? Daarvoor heb je geen object nodig: je stopt er getallen in en krijgt een getal terug, net zoals bij Math.Pow. Een klus voor een static class.
Specificaties:
- Klassenaam:
Puntenrekenaar, eenstatic class. - Static property
AantalBerekeningen(int, privateset): telt hoe vaak een van de twee methoden opgeroepen werd. - Static methode
double NaarTwintig(double score, double maximum): zet een score om naar een score op 20. 39 op 60 wordt 13. - Static methode
double NodigOpExamen(double peOpTwintig, int procentExamen): hoeveel je op 20 nodig hebt op het examen om samen 10 op 20 te halen.procentExamenzegt hoeveel procent het examen meetelt; de permanente evaluatie telt voor de rest. Gebruik deze formule:deelExamen=procentExamen / 100.0deelPe=(100 - procentExamen) / 100.0- nodig =
(10 - peOpTwintig * deelPe) / deelExamen
- Beide methoden tonen met
Debug.WriteLinewat ze berekend hebben, bv.NaarTwintig: 39 op 60 is 13 op 20.
Testcode. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
double programmeren = Puntenrekenaar.NaarTwintig(39, 60);
Console.WriteLine($"Programmeren, permanente evaluatie: {programmeren:F1} op 20");
Console.WriteLine($"Nodig op het examen (telt 60%): {Puntenrekenaar.NodigOpExamen(programmeren, 60):F1} op 20");
double wiskunde = Puntenrekenaar.NaarTwintig(9, 30);
Console.WriteLine($"Wiskunde, permanente evaluatie: {wiskunde:F1} op 20");
Console.WriteLine($"Nodig op het examen (telt 50%): {Puntenrekenaar.NodigOpExamen(wiskunde, 50):F1} op 20");
Console.WriteLine($"Aantal berekeningen: {Puntenrekenaar.AantalBerekeningen}");Programmeren, permanente evaluatie: 13,0 op 20
Nodig op het examen (telt 60%): 8,0 op 20
Wiskunde, permanente evaluatie: 6,0 op 20
Nodig op het examen (telt 50%): 14,0 op 20
Aantal berekeningen: 4
Daarna:
- Start je programma met de debugger (F5). Waar vind je de tekst van
Debug.WriteLine? - Schrijf in
MainPuntenrekenaar rekenaar = new Puntenrekenaar();. Wat zegt de compiler? - Haal die lijn weg en voeg aan de klasse een gewone methode toe:
public void ToonUitleg(). Wat zegt de compiler nu?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Een static class is een bibliotheek van methoden, zoals
Math. Je roept alles op via de klassenaam. Zie Static methoden en klassen. - Schrijf
100.0en niet100:60 / 100is een gehele deling en geeft 0. Debug.WriteLineschrijft naar het venster Output, niet naar de console. Zie Intermezzo: Debug.WriteLine.
Pokémon deel 2 (Essential)
We bouwen verder op de Pokemon-klasse uit hoofdstuk 10: de base-stats met hun controle, ShowInfo uit de Pokémontester, en GeneratorPokemon en Battle uit de Pokémon-battler. Maak een kopie van dat project: een deel van je oude Main zal straks niet meer compileren.
Deel 1: constructors. Base-stats veranderen nooit (het dna, weet je nog?). Toch kon iedereen ze tot nu toe aanpassen.
- Geef de
setvan de zes base-stats eenprivateervoor. De controle (1 tot en met 255) blijft staan. - Voeg een constructor toe met zes
int-parameters, in de volgorde HP, attack, defense, special attack, special defense en speed. Hij vult de base-stats in via de properties, zodat de controle ook hier werkt. - Voeg een default constructor toe die alle zes base-stats op 10 zet. Gebruik
: this(...).
Naam, Nummer en Type houden hun public set. Die geef je mee met een initializer, ook achter de constructor met zes parameters.
Testcode deel 1.
Pokemon pikachu = new Pokemon(35, 55, 40, 50, 50, 90) { Naam = "Pikachu", Nummer = 25, Type = "electric" };
Pokemon oefenpop = new Pokemon { Naam = "Oefenpop" };
for (int i = 0; i < 50; i++)
{
pikachu.VerhoogLevel();
}
pikachu.ShowInfo();
oefenpop.ShowInfo();
try
{
Pokemon fout = new Pokemon(35, 55, 40, 50, 50, 300);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}Pikachu (#25, electric), level 50
Base stats: HP 35, attack 55, defense 40, sp. attack 50, sp. defense 50, speed 90
Full stats: HP 95, attack 60, defense 45, sp. attack 55, sp. defense 55, speed 95
Total 320, average 53,33
Oefenpop (#0, onbekend), level 0
Base stats: HP 10, attack 10, defense 10, sp. attack 10, sp. defense 10, speed 10
Full stats: HP 10, attack 5, defense 5, sp. attack 5, sp. defense 5, speed 5
Total 60, average 10,00
Speed_Base moet tussen 1 en 255 liggen.
Zet daarna HP_Base = 40 in de initializer van oefenpop. Wat zegt de compiler?
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
Deel 2: static. In je Program.cs staat nog de GeneratorPokemon uit de battler. Wat zegt de compiler nu over die methode, en waarom?
Dat lossen we op door GeneratorPokemon en Battle naar de klasse Pokemon te verhuizen. Ze blijven static: ze horen bij geen enkele Pokémon in het bijzonder. In de klasse komen er ook tellers bij over alle Pokémon samen.
- Static properties met een private
set:TellerLevel(hoe vaakVerhoogLevelin totaal geleveld heeft),TellerBattles,TellerGelijkspelenTellerGeneraties(hoe vaakGeneratorPokemonopgeroepen werd). - Static property
NoLevelingAllowed(bool) met een publicset. VerhoogLevel: isNoLevelingAllowedtrue, dan werpt ze eenExceptionop met de boodschapLevelen is niet toegelaten.Anders verhoogt ze het level enTellerLevel.public static Pokemon GeneratorPokemon(string naam): zoals in de battler (base-stats van 20 tot en met 150, level van 1 tot en met 50), maar nu met de constructor met zes parameters. DeRandomkomt niet meer uitMain: de klasse krijgt éénprivate static Random. Het level zet de methode rechtstreeks metLevel: binnen de klasse mag dat, want de privatesethoort bij de klasse. Ze verhoogtTellerGeneraties.public static int Battle(Pokemon poke1, Pokemon poke2): zoals in de battler, maar ze verhoogtTellerBattles(na de controle opnull) en bij gelijkspel ookTellerGelijkspel.public static void Info(): toont de tellers, zoals in de uitvoer hieronder.
Testcode deel 2.
Pokemon pikachu = new Pokemon(35, 55, 40, 50, 50, 90) { Naam = "Pikachu" };
Pokemon bulbasaur = new Pokemon(45, 49, 49, 65, 65, 45) { Naam = "Bulbasaur" };
Pokemon spiegel = new Pokemon(35, 55, 40, 50, 50, 90) { Naam = "Spiegel-Pikachu" };
for (int i = 0; i < 10; i++)
{
pikachu.VerhoogLevel();
bulbasaur.VerhoogLevel();
spiegel.VerhoogLevel();
}
Console.WriteLine($"Pikachu tegen Bulbasaur: {Pokemon.Battle(pikachu, bulbasaur)}");
Console.WriteLine($"Pikachu tegen Spiegel-Pikachu: {Pokemon.Battle(pikachu, spiegel)}");
Pokemon wild = Pokemon.GeneratorPokemon("Wilde Rattata");
Console.WriteLine($"{wild.Naam} verschijnt.");
Pokemon.NoLevelingAllowed = true;
try
{
pikachu.VerhoogLevel();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Pokemon.Info();Pikachu tegen Bulbasaur: 1
Pikachu tegen Spiegel-Pikachu: 0
Wilde Rattata verschijnt.
Levelen is niet toegelaten.
Aantal keer geleveld: 30
Aantal battles: 2, waarvan 1 gelijkspel
Aantal gegenereerd: 1
Waarom telt TellerLevel de levels van wild niet mee?
Student Kevin Van Rooy maakte volgende applicatie waarbij bovenstaande opgave als initiële inspiratie diende:

Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- De default constructor gebruikt de constructor met zes parameters via
: this(...). De toekenningen staan maar één keer in je code. - Een constructor vult properties in via hun
set, dus de controle uit hoofdstuk 10 werkt meteen ook bijnew. - Een private
setis bereikbaar overal in de klasse, ook in een static methode. Daarom verhuistGeneratorPokemonnaarPokemon. - Tellers over alle Pokémon samen zijn
static. Zie Static properties.
Pokémon natures (PRO)
Pokémon hebben een nature (aard). Die verhoogt één stat met 10% en verlaagt een andere met 10%. Bouw verder op je klasse uit Pokémon deel 2.
Specificaties:
- Enums: een enum
Naturemet de 25 natures uit de tabel hieronder, en een enumStatTypemetAttack,Defense,SpecialAttack,SpecialDefenseenSpeed. HP staat er niet in: een nature verandert de HP niet. - Property:
Nature(van het typeNature), met een privateset. - Constructor: elke nieuwe Pokémon krijgt een willekeurige nature. Doe dat in de constructor met zes parameters en gebruik dezelfde
private static RandomalsGeneratorPokemon. Waarom krijgt een Pokémon die metnew Pokemon()gemaakt wordt dan ook een nature? - Helpermethode:
private double BerekenNatureModifier(StatType stat). Ze geeft1.10terug als de nature deze stat verhoogt,0.90als ze deze stat verlaagt, en anders1.0. Vijf natures (Bashful, Docile, Hardy, Quirky en Serious) verhogen en verlagen dezelfde stat. Die veranderen niets: geef1.0terug. - Full-stats: vermenigvuldig het resultaat van elke full-stat, behalve
HP_Full, met die factor en cast terug naarint.
| Nature | Verhoogt met 10% | Verlaagt met 10% |
|---|---|---|
| Adamant | Attack | Sp. Atk |
| Bashful | Sp. Atk | Sp. Atk |
| Bold | Defense | Attack |
| Brave | Attack | Speed |
| Calm | Sp. Def | Attack |
| Careful | Sp. Def | Sp. Atk |
| Docile | Defense | Defense |
| Gentle | Sp. Def | Defense |
| Hardy | Attack | Attack |
| Hasty | Speed | Defense |
| Impish | Defense | Sp. Atk |
| Jolly | Speed | Sp. Atk |
| Lax | Defense | Sp. Def |
| Lonely | Attack | Defense |
| Mild | Sp. Atk | Defense |
| Modest | Sp. Atk | Attack |
| Naive | Speed | Sp. Def |
| Naughty | Attack | Sp. Def |
| Quiet | Sp. Atk | Speed |
| Quirky | Sp. Def | Sp. Def |
| Rash | Sp. Atk | Sp. Def |
| Relaxed | Defense | Speed |
| Sassy | Sp. Def | Speed |
| Serious | Speed | Speed |
| Timid | Speed | Attack |
Testen. Maak in een lus drie keer een Pikachu (dezelfde base-stats als in deel 1), laat hem 50 keer levelen en toon zijn nature en Speed_Full. Zonder nature was dat 95. Bij jou komen er andere natures uit, bijvoorbeeld:
Pikachu is Jolly: speed 104
Pikachu is Brave: speed 85
Pikachu is Hardy: speed 95
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Wat elke Pokémon bij zijn geboorte krijgt, hoort in de hoofdconstructor. Via
: this(...)krijgen de andere constructors het vanzelf mee. - Eén helpermethode voor de factor, zodat de vijf full-stats elk maar één vermenigvuldiging hebben.
Project: GreenRide (Final Essentials)
Je bent net aangenomen bij GreenRide, een nieuwe start-up met elektrische deelsteps in ’t Stad. Er is nog geen software: jij schrijft de klasse die de steps beheert, de winst bijhoudt en ervoor zorgt dat niemand vertrekt met een lege batterij.
Denk bij elk gegeven na: hoort het bij één step, of bij het hele bedrijf? Wat bij het hele bedrijf hoort, is static.
De klasse DeelStep
Gegevens van het bedrijf (static):
PrijsPerMinuut(double): de ritprijs per minuut, een auto-property met een publicseten beginwaarde0.25euro. De directie kan ze veranderen, bv. als het regent.TotaalWinst(double): hoeveel euro alle steps samen al opgebracht hebben. Privateset.AantalInGebruik(int): hoeveel steps er op dit moment rondrijden. Privateset.volgNummerGenerator(private static int, begint op 1): het nummer dat de volgende step krijgt.
Gegevens van één step:
ID(int): het unieke nummer van de step. Privateset.BatterijNiveau(int): full property met een privateset. Een waarde onder 0 wordt 0, een waarde boven 100 wordt 100.IsBezig(bool): is de step verhuurd? Privateset.
Constructors:
DeelStep(int batterij): voor een step die uit onderhoud komt. ZetBatterijNiveauop de meegegeven waarde, geef de step alsIDhet nummer vanvolgNummerGeneratoren verhoog die daarna met 1.DeelStep(): een nieuwe step met 100% batterij. Gebruik: this(...).
Methoden:
StartRit():- Is de step al onderweg, toon dan
Step {ID} is al onderweg. - Is de batterij 10% of minder, toon dan
Step {ID} kan niet vertrekken: batterij te laag ({BatterijNiveau}%). - Anders:
IsBezigwordttrue,AantalInGebruikgaat 1 omhoog, en je toontStep {ID} vertrekt met {BatterijNiveau}% batterij.
- Is de step al onderweg, toon dan
EindigRit(int aantalMinuten):- Was de step niet onderweg, toon dan
Step {ID} was niet onderweg. - Anders:
IsBezigwordtfalseenAantalInGebruikgaat 1 omlaag. De ritprijs isaantalMinuten * PrijsPerMinuuten gaat bijTotaalWinst. Elke minuut rijden kost 1% batterij. ToonStep {ID} terug. Ritprijs: {ritprijs:F2} euro. Resterende batterij: {BatterijNiveau}%
- Was de step niet onderweg, toon dan
Het dashboard in Main
- De vloot: maak drie steps. Step 1 en 2 zijn nieuw, step 3 komt uit onderhoud met 5% batterij.
- De ochtendspits: laat step 1, 2 en 3 vertrekken en toon hoeveel steps er in gebruik zijn.
- Het begint te regenen: de directie zet
DeelStep.PrijsPerMinuut = 0.50;. - De aankomst: step 1 stopt na 20 minuten, step 2 na 10 minuten. Toon opnieuw hoeveel steps er in gebruik zijn.
- De balans: toon de totale winst en de batterij van step 1.
Zo hoort het eruit te zien:
Step 1 vertrekt met 100% batterij.
Step 2 vertrekt met 100% batterij.
Step 3 kan niet vertrekken: batterij te laag (5%).
Steps in gebruik: 2
Step 1 terug. Ritprijs: 10,00 euro. Resterende batterij: 80%
Step 2 terug. Ritprijs: 5,00 euro. Resterende batterij: 90%
Steps in gebruik: 0
Totale winst: 15,00 euro
Batterij step 1: 80%
Deze oplossing is afgeschermd.
Studenten krijgen de sleutel van hun lesgever. Heb je de sleutel al eens op dit toestel
gebruikt, dan verschijnt de oplossing hier vanzelf.
- Static of niet? De prijs, de winst en het aantal steps onderweg gaan over het hele bedrijf; de batterij en het ID over één step. Een static property spreek je aan via de klassenaam:
DeelStep.PrijsPerMinuut. - Een static teller (
volgNummerGenerator) geeft elk nieuw object een eigen nummer. Was hij niet static, dan kreeg elke step nummer 1. - De batterijcontrole staat in de
set, dus ze werkt in de constructor én inEindigRit. - De ritprijs gebruikt de prijs op het moment van afrekenen: beide ritten kosten 0,50 euro per minuut, ook al vertrokken ze toen de prijs nog 0,25 was.