- Controleer op
nullvóór je het eerste puntje achter een object zet. - Zet een specifieke
catchvóórcatch (Exception e). Een leegcatch-blok is geen oplossing: toon minstens wat er misliep, bv. mete.Message(uitleg). - Een methode in
Program.csblijftstatic, ook als ze een object krijgt of teruggeeft. - Groene kronkels zoals
CS8600,CS8603ofCS8604bijnullmag je laten staan (uitleg).
Kleur mixer (Essential)
Doel: Meng twee kleuren door het gemiddelde te nemen van hun RGB-waarden.

Deel 1. Een kleur die verandert.
- Klassenaam:
Kleur - Properties:
Rood,GroenenBlauw, alle drie auto-properties van het typeint. - Methode:
MengKleur(Kleur andereKleur)(void).
Wanneer MengKleur wordt aangeroepen, veranderen de properties van de huidige kleur (het object waarop je de methode aanroept). De kleur die je als parameter meegeeft, verandert niet. Gebruik deze formules (gehele deling):
- Nieuw rood =
(huidig rood + ander rood) / 2 - Nieuw groen =
(huidig groen + ander groen) / 2 - Nieuw blauw =
(huidig blauw + ander blauw) / 2
Testcode deel 1. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
Kleur k1 = new Kleur();
k1.Rood = 10;
k1.Groen = 0;
k1.Blauw = 20;
Kleur k2 = new Kleur();
k2.Rood = 10;
k2.Groen = 10;
k2.Blauw = 50;
k1.MengKleur(k2);
Console.WriteLine($"{k1.Rood},{k1.Groen},{k1.Blauw}");10,5,35
Voeg daarna een lijn toe die ook k2 toont. Welke getallen verwacht je, nog voor je het uitvoert?
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 nieuwe kleur.
Soms wil je beide kleuren houden. Voeg een methode Kleur Meng(Kleur andereKleur) toe. Ze rekent met dezelfde formules, maar verandert geen van beide kleuren: ze maakt een nieuwe Kleur en geeft die terug.
Testcode deel 2.
Kleur geel = new Kleur();
geel.Rood = 255;
geel.Groen = 255;
geel.Blauw = 0;
Kleur blauw = new Kleur();
blauw.Blauw = 255;
Kleur mix = geel.Meng(blauw);
Console.WriteLine($"Geel: {geel.Rood},{geel.Groen},{geel.Blauw}");
Console.WriteLine($"Blauw: {blauw.Rood},{blauw.Groen},{blauw.Blauw}");
Console.WriteLine($"Mix: {mix.Rood},{mix.Groen},{mix.Blauw}");Geel: 255,255,0
Blauw: 0,0,255
Mix: 127,127,127
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 methode die een object meekrijgt, krijgt het adres. Ze kan dat object aanpassen, maar het hoeft niet:
MengKleurleestandereKleurenkel uit. MengKleurverandert het object waarop je ze aanroept.Mengmaakt metneween derde object en geeft het terug; het returntype is danKleur.- Zie Objecten in methoden aanpassen en Objecten als resultaat.
Voorspel de uitvoer: de geleende fiets (Essential)
Je kotgenoot vraagt of hij je fiets mag lenen. Natuurlijk. Maar wat gebeurt er met jouw fiets terwijl hij weg is? Bekijk deze klasse en dit programma. Typ niets over. Schrijf eerst op papier wat elk van de zes genummerde lijnen toont.
internal class Fiets
{
public string Eigenaar { get; set; } = "niemand";
public string Kleur { get; set; } = "zwart";
public int Kilometers { get; set; }
public void Rij(int km)
{
Kilometers = Kilometers + km;
}
}static void Main(string[] args)
{
Fiets mijnFiets = new Fiets();
mijnFiets.Eigenaar = "Lotte";
mijnFiets.Kilometers = 1200;
Fiets geleend = mijnFiets;
geleend.Kleur = "groen";
geleend.Rij(4);
Console.WriteLine($"1. {mijnFiets.Kleur}, {mijnFiets.Kilometers} km");
int teller = mijnFiets.Kilometers;
teller = teller + 100;
Console.WriteLine($"2. {mijnFiets.Kilometers} km, teller {teller}");
VoegRitToe(teller);
Console.WriteLine($"3. teller {teller}");
BrengNaarCampus(mijnFiets);
Console.WriteLine($"4. {mijnFiets.Kilometers} km");
mijnFiets.Eigenaar.ToUpper();
Console.WriteLine($"5. {mijnFiets.Eigenaar}");
Fiets oudeFiets = new Fiets();
oudeFiets.Eigenaar = "Jonas";
oudeFiets = geleend;
Console.WriteLine($"6. {oudeFiets.Eigenaar}, {oudeFiets.Kleur}");
}
static void VoegRitToe(int km)
{
km = km + 10;
}
static void BrengNaarCampus(Fiets fiets)
{
fiets.Rij(5);
}Beantwoord daarna:
- Teken de stack en de heap na de laatste lijn van
Main. HoeveelFiets-objecten staan er in de heap, en welke variabelen wijzen naar welk object? - Welk object mag de Garbage Collector opruimen?
Voer het programma pas daarna uit en vergelijk met je voorspelling.
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 een object kopieert de referentie, bij eenintde waarde. Zie = operator bij value types en = operator bij objecten.- Een methode met een
int-parameter werkt op een kopie, een methode met een object als parameter op het origineel. - Een object waar geen enkele variabele meer naar wijst, is onbereikbaar en wordt door de Garbage Collector opgeruimd.
ToUpper()verandert eenstringniet. Zie Wat met string?.
Pokémon (Essential)
We schrijven een klasse die de stats van een Pokémon berekent terwijl hij levelt. Deze klasse komt terug in de volgende oefeningen en in hoofdstuk 11.
Hoe Pokémon werken. Elke Pokémon heeft zes base-stats. Die zijn voor elke soort anders en veranderen nooit: je kan ze als het dna van een Pokémon zien. De full-stats bepalen hoe sterk hij is in een gevecht. Ze worden berekend uit de base-stats en het huidige level: hoe hoger het level, hoe hoger de full-stats.


Maak een klasse Pokemon (in code zonder é) met:
Base-stats. Zes full properties van het type int: HP_Base, Attack_Base, Defense_Base, SpecialAttack_Base, SpecialDefense_Base en Speed_Base. Een base-stat ligt altijd tussen 1 en 255. Krijgt de set een waarde daarbuiten, dan werpt hij een Exception op met als boodschap de naam van de property, gevolgd door moet tussen 1 en 255 liggen. (bv. HP_Base moet tussen 1 en 255 liggen.). De instantievariabele verandert dan niet.
Extra stats. Drie auto-properties: Naam (string), Type (string, bv. grass & poison) en Nummer (int, het nummer in de Pokédex: Bulbasaur heeft 1, Pikachu 25).
Level. Een full property Level (int) met een public get en een private set. Een nieuwe Pokémon start op level 0. De methode VerhoogLevel() verhoogt het level met 1, zonder parameters en zonder returnwaarde.
Statistieken. Twee read-only properties:
Total(int): de som van de zes base-stats.Average(double): het gemiddelde van de zes base-stats, dusTotal / 6.0.
Full-stats. Zes read-only properties van het type int, die telkens rekenen in hun get:
HP_Full=(((HP_Base + 50) * Level) / 50) + 10Attack_Full,Defense_Full,SpecialAttack_Full,SpecialDefense_FullenSpeed_Full=((stat_Base * Level) / 50) + 5. BijvoorbeeldAttack_Full=((Attack_Base * Level) / 50) + 5.
De statistieken en de full-stats bewaren niets: ze hebben geen eigen instantievariabele. Omdat de formules met int rekenen, stijgen de full-stats niet bij elk level, maar pas om de paar levels.
Testcode. Zet deze code in je Main. Je klasse werkt als je exact deze uitvoer krijgt.
Pokemon pikachu = new Pokemon();
pikachu.Naam = "Pikachu";
pikachu.Nummer = 25;
pikachu.Type = "electric";
pikachu.HP_Base = 35;
pikachu.Attack_Base = 55;
pikachu.Defense_Base = 40;
pikachu.SpecialAttack_Base = 50;
pikachu.SpecialDefense_Base = 50;
pikachu.Speed_Base = 90;
Console.WriteLine($"{pikachu.Naam} (#{pikachu.Nummer}, {pikachu.Type}) start op level {pikachu.Level}");
Console.WriteLine($"Total {pikachu.Total}, average {pikachu.Average:F2}");
Console.WriteLine($"HP {pikachu.HP_Full}, attack {pikachu.Attack_Full}, speed {pikachu.Speed_Full}");
for (int i = 0; i < 50; i++)
{
pikachu.VerhoogLevel();
}
Console.WriteLine($"Level {pikachu.Level}: HP {pikachu.HP_Full}, attack {pikachu.Attack_Full}, defense {pikachu.Defense_Full}");
Console.WriteLine($"sp. attack {pikachu.SpecialAttack_Full}, sp. defense {pikachu.SpecialDefense_Full}, speed {pikachu.Speed_Full}");
Console.WriteLine($"Total {pikachu.Total}, average {pikachu.Average:F2}");
try
{
pikachu.Speed_Base = 300;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine($"Speed_Base is nog altijd {pikachu.Speed_Base}");Pikachu (#25, electric) start op level 0
Total 320, average 53,33
HP 10, attack 5, speed 5
Level 50: HP 95, attack 60, defense 45
sp. attack 55, sp. defense 55, speed 95
Total 320, average 53,33
Speed_Base moet tussen 1 en 255 liggen.
Speed_Base is nog altijd 90
Maak daarna zelf nog een paar Pokémon met de base-stats uit deze lijst. Je stelt enkel de base-stats in: al de rest volgt daaruit en uit het level.
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.
- Bewaar enkel wat je niet kan berekenen. De zes base-stats en het level zijn genoeg;
Total,Averageen de full-stats rekenen telkens opnieuw in hunget. - De
setwerpt een exception op en zegt zo aan wie hem oproept dat er iets misliep. Wat er dan moet gebeuren, beslist de code die de property gebruikt, met eencatch. Zie Een exception genereren met throw. Levelheeft een privateset: enkelVerhoogLevelkan het level veranderen.
Stevens reservekopie (Essential)
Stagiair Steven werkt met de Pokémon-klasse uit de vorige oefening. Hier is ze ingekort: enkel de stats die hij nodig heeft, met auto-properties voor de base-stats. Level en de formules van HP_Full en Attack_Full zijn dezelfde als in de opgave.
internal class Pokemon
{
public string Naam { get; set; } = "Onbekend";
public int HP_Base { get; set; }
public int Attack_Base { get; set; }
private int level;
public int Level
{
get { return level; }
private set { level = value; }
}
public void VerhoogLevel()
{
Level++;
}
public int HP_Full
{
get { return (((HP_Base + 50) * Level) / 50) + 10; }
}
public int Attack_Full
{
get { return ((Attack_Base * Level) / 50) + 5; }
}
}Steven wil tonen wat tien levels training met zijn Pikachu doen. Hij vroeg een A.I. om eerst een reservekopie te nemen, zodat hij voor en na kan vergelijken, en om Pikachu daarna tegen een rivaal te laten vechten. MaakRivaal kent voorlopig enkel Onix. Steven test bewust met een rivaal die zijn programma niet kent, om te zien of zijn foutmelding werkt. Dit zette de A.I. in Program.cs:
static void Main(string[] args)
{
Pokemon pikachu = new Pokemon();
pikachu.Naam = "Pikachu";
pikachu.HP_Base = 35;
pikachu.Attack_Base = 55;
Pokemon reserve = pikachu; // reservekopie van voor de training
for (int i = 0; i < 10; i++)
{
pikachu.VerhoogLevel();
}
Console.WriteLine($"Voor de training: level {reserve.Level}, HP {reserve.HP_Full}");
Console.WriteLine($"Na de training: level {pikachu.Level}, HP {pikachu.HP_Full}");
Pokemon rivaal = MaakRivaal("Mew");
try
{
int winnaar = Battle(pikachu, rivaal);
Console.WriteLine($"Winnaar: Pokémon {winnaar}");
}
catch (Exception e)
{
Console.WriteLine($"Geen gevecht: {e.Message}");
}
}
static Pokemon MaakRivaal(string naam)
{
Pokemon rivaal = null;
if (naam == "Onix")
{
rivaal = new Pokemon();
rivaal.Naam = "Onix";
rivaal.HP_Base = 35;
rivaal.Attack_Base = 45;
}
return rivaal;
}
static int Battle(Pokemon poke1, Pokemon poke2)
{
int kracht1 = poke1.HP_Full + poke1.Attack_Full;
int kracht2 = poke2.HP_Full + poke2.Attack_Full;
if (poke1 == null || poke2 == null)
{
throw new Exception("Een gevecht heeft twee Pokémon nodig.");
}
int winnaar = 0;
if (kracht1 > kracht2)
{
winnaar = 1;
}
else if (kracht2 > kracht1)
{
winnaar = 2;
}
return winnaar;
}Deel 1. Het compileert zonder foutmeldingen en het crasht niet. Een nieuwe Pokémon start op level 0, dus Steven verwacht als eerste lijn Voor de training: level 0, HP 10. Voer het uit. Wat krijgt hij, en waarom? Pas het stuk rond reserve aan, zodat reserve echt de Pikachu van voor de training bewaart.
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. Kijk naar de laatste lijn van de uitvoer. Is dat de melding die Steven in Battle schreef? Zoek waar ze vandaan komt, en pas Battle aan zodat Steven zijn eigen melding te zien krijgt.
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 compiler vindt geen van beide fouten, en het programma crasht niet. Enkel de uitvoer verraadt dat er iets mis is.
=bij een object kopieert de referentie, niet het object. Zie = operator bij objecten.- Controleer op
nullvóór je het eerste puntje achter het object zet. Zie NullReferenceException voorkomen. catch (Exception e)vangt ook uitzonderingen op die je niet verwacht. Hier toondee.Messagedat het niet om Stevens eigen exception ging. Zie Werken met de exception parameter.
Kies je starter (Essential)
Elke Pokémontrainer begint met één van drie starters. Schrijf in Program.cs een methode static Pokemon KiesStarter(string naam) die je Pokemon-klasse gebruikt:
| Naam | Nummer | Type | HP | Attack | Defense | Sp. attack | Sp. defense | Speed |
|---|---|---|---|---|---|---|---|---|
| Bulbasaur | 1 | grass & poison | 45 | 49 | 49 | 65 | 65 | 45 |
| Charmander | 4 | fire | 39 | 52 | 43 | 60 | 50 | 65 |
| Squirtle | 7 | water | 44 | 48 | 65 | 50 | 64 | 43 |
Is naam een van die drie, dan maakt de methode die Pokémon aan, vult alles in en geeft hem terug. Voor elke andere naam geeft ze null terug.
Deel 1. Zet deze code in je Main:
Pokemon eerste = KiesStarter("Charmander");
Console.WriteLine($"Je koos {eerste?.Naam}, total {eerste?.Total}");
Pokemon tweede = KiesStarter("Pikachu");
Console.WriteLine($"Je koos {tweede?.Naam}, total {tweede?.Total}");
Pokemon derde = KiesStarter("squirtle");
Console.WriteLine($"Je koos {derde?.Naam}, total {derde?.Total}");Je koos Charmander, total 309
Je koos , total
Je koos , total
Waarom zijn de laatste twee lijnen leeg? Haal daarna bij tweede de twee vraagtekens weg. Wat gebeurt er 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.
Deel 2. Vraag de gebruiker welke starter hij wil, tot hij een naam typt die KiesStarter kent. Toon daarna zijn keuze.
Kies je starter: Bulbasaur, Charmander of Squirtle
>Pikachu
Die starter ken ik niet.
Kies je starter: Bulbasaur, Charmander of Squirtle
>charmander
Die starter ken ik niet.
Kies je starter: Bulbasaur, Charmander of Squirtle
>Charmander
Charmander (#4, fire) is je eerste Pokémon!
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 methode mag een object teruggeven, en
nullals er niets te geven is. Wie de methode oproept, moet dat dan wel controleren. Zie Return null. object?.Naamis de verkorte null-controle: geen crash, maar ook geen naam. Zie Verkorte null controle notatie.nullkan je ook als voorwaarde in een lus gebruiken:while (gekozen == null).
Pokémontester (Essential)
Deel 1: ShowInfo. Het is een heel gedoe om telkens alle stats van een Pokémon apart op het scherm te zetten. Voeg aan je Pokemon-klasse een methode public void ShowInfo() toe die alles toont, in deze vorm:
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
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 nieuw project.
- Maak een nieuwe console-applicatie “PokemonTester”.
- Voeg het bestand van je
Pokemon-klasse toe: rechtsklik op het project, Add > Existing Item… en kiesPokemon.csuit je vorige project. - Schrijf in
MainPokemon test = new Pokemon();. Er verschijnt een rode kronkel onderPokemon. Waarom? Los het op via het lampje. Welke twee opties biedt Visual Studio je? - Draai je keuze terug en pas nu de
namespacebovenaanPokemon.csaan naar die van het nieuwe project. Wat gebeurt er met de kronkel?
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: invoer die niet crasht. Schrijf een programma dat de gebruiker de naam en de zes base-stats van een Pokémon vraagt, de Pokémon toont met ShowInfo, vraagt hoeveel keer hij moet levelen, en hem daarna opnieuw toont.
Een gebruiker typt niet altijd wat je verwacht. Letters, een kommagetal, een getal van twaalf cijfers of een stat van 400 mogen je programma niet laten crashen.
- Zoek eerst in de documentatie van
Convert.ToInt32(String)welke exceptions die methode kan opwerpen, en wanneer. - Versie 1: zet alles in één
try. Vang de twee exceptions uit de documentatie elk apart op, met een eigen melding, en zet als laatstecatch (Exception e), diee.Messagetoont. Die vangt de exception op die jesetopwerpt bij een stat buiten 1-255.
Naam?
>Pikachu
HP?
>35
Attack?
>vijftig
Dat is geen geheel getal.
- Versie 2: bij een foute stat begint de gebruiker in versie 1 helemaal opnieuw. Schrijf een methode
static void VraagStat(Pokemon poke, string stat)die één stat vraagt en blijft vragen tot de waarde geldig is: een lus met eenbool, en detryin de lus. Gebruik geenbreakom uit de lus te springen. Roep ze op voor de zes stats. Is het aantal levels geen geldig getal, dan blijft de Pokémon op level 0.
Naam?
>Pikachu
HP?
>35
Attack?
>vijftig
Dat is geen geheel getal.
Attack?
>55
Defense?
>400
Defense_Base moet tussen 1 en 255 liggen.
Defense?
>40
SpecialAttack?
>99999999999
Dat getal is veel te groot.
SpecialAttack?
>50
SpecialDefense?
>50
Speed?
>90
Pikachu (#0, onbekend), level 0
Base stats: HP 35, attack 55, defense 40, sp. attack 50, sp. defense 50, speed 90
Full stats: HP 10, attack 5, defense 5, sp. attack 5, sp. defense 5, speed 5
Total 320, average 53,33
Hoeveel keer moet je Pokémon levelen?
>50
Pikachu (#0, onbekend), 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
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 klasse die je in een ander project gebruikt, vind je via
usingof via haar volledige naam. Zie Ontbrekende namespaces terugvinden. - Welke exceptions een methode opwerpt, staat in de documentatie. Zie Welke exceptions worden gegooid?.
- Specifieke
catch-blokken eerst,catch (Exception e)laatst. Zie Meerdere catchblokken. - Waar de
trystaat, bepaalt wat er opnieuw moet: ééntryrond alles stopt bij de eerste fout, eentryin de lus vraagt enkel die ene waarde opnieuw. Zie Waar exception handling in code plaatsen?.
Pokémon-battler (Essential)
Tijd om te vechten. Beide methoden hieronder staan in Program.cs, niet in de klasse: ze horen niet bij één Pokémon.
Pokémon-generator. Schrijf static Pokemon GeneratorPokemon(string naam, Random generator). De methode maakt een Pokémon met die naam, zes willekeurige base-stats tussen 20 en 150, en een willekeurig level tussen 1 en 50 (roep VerhoogLevel zoveel keer op). Ze geeft de Pokémon terug. Maak in Main één Random en geef die telkens mee.
Battle. Schrijf static int Battle(Pokemon poke1, Pokemon poke2). Ze geeft 1 terug als poke1 wint, 2 als poke2 wint en 0 bij gelijkspel. Wie wint, bepaal je zelf, maar gebruik de full-stats: dan speelt het level mee. (Gewoon de levels vergelijken telt niet.) Is poke1 of poke2 null, dan werpt Battle een Exception op met de boodschap Battle kan niet doorgaan: een van beide Pokémon is null.
In Main.
- Genereer twee wilde Pokémon, toon ze met
ShowInfoen laat ze vechten. Toon wie wint. - Roep daarna
Battle(links, niemand)op, metPokemon niemand = null;. Doe dat eerst zondertry. Wat zie je? - Zet die oproep nu in een
tryen toon in decatche.Message.
Wilde Rattata (#0, onbekend), level 27
Base stats: HP 25, attack 85, defense 66, sp. attack 107, sp. defense 79, speed 144
Full stats: HP 50, attack 50, defense 40, sp. attack 62, sp. defense 47, speed 82
Total 506, average 84,33
Wilde Pidgey (#0, onbekend), level 8
Base stats: HP 72, attack 95, defense 40, sp. attack 47, sp. defense 62, speed 90
Full stats: HP 29, attack 20, defense 11, sp. attack 12, sp. defense 14, speed 19
Total 406, average 67,67
Wilde Rattata wint!
Geen gevecht: Battle kan niet doorgaan: een van beide Pokémon is null.
Bij jou komen er andere getallen uit.
Uitbreiding. Zet de gevechten in een lus: de winnaar levelt na elk gevecht, de verliezer wordt vervangen door een nieuwe wilde Pokémon. Hoe lang houdt je kampioen het vol?
Bonus: hoe snel is je battle? Hoe lang duurt het om een miljoen gevechten uit te rekenen? Daarvoor bestaat de klasse Stopwatch: Start() zet ze aan, Stop() zet ze stil, en de property ElapsedMilliseconds geeft het aantal milliseconden daartussen. Typ Stopwatch klok = new Stopwatch();. Waarom kent C# die klasse niet, en hoe los je dat op?
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.
Battlecontroleert zelf wat het binnenkrijgt en werpt een exception op. Zondercatchstopt je programma met die boodschap; met eencatchbeslistMainwat er gebeurt.GeneratorPokemonmaakt een object aan en geeft het terug.Mainheeft daarna een referentie naar een Pokémon die in de methode gemaakt werd.- Eén
Randomvoor het hele programma: maak hem inMainen geef hem mee. - Een klasse uit .NET die C# niet vindt, staat meestal in een namespace die je nog niet geladen hebt. Zie using in je code.
Voorspel de uitvoer: printen in de bib (Essential)
De avond voor het examen print je in de bib nog snel drie bestanden. De printer neemt enkel pdf’s aan. Dit is het programma, met een lege plek in Main:
static void Main(string[] args)
{
string[] bestanden = { "samenvatting.pdf", "notities.docx", "oefeningen.pdf" };
// hier komt versie 1, 2 of 3
Console.WriteLine("Op naar huis.");
}
static void Print(string bestand)
{
if (!bestand.EndsWith(".pdf"))
{
throw new Exception($"{bestand} is geen pdf.");
}
Console.WriteLine($"{bestand} geprint.");
}Op de lege plek komt telkens een van deze drie versies:
// Versie 1
for (int i = 0; i < bestanden.Length; i++)
{
Print(bestanden[i]);
}// Versie 2
try
{
for (int i = 0; i < bestanden.Length; i++)
{
Print(bestanden[i]);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
Console.WriteLine("Printer vrijgegeven.");
}// Versie 3
for (int i = 0; i < bestanden.Length; i++)
{
try
{
Print(bestanden[i]);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
Console.WriteLine("Printer vrijgegeven.");
}
}En dit zijn de drie uitvoeren, door elkaar:
Uitvoer A
samenvatting.pdf geprint.
Printer vrijgegeven.
notities.docx is geen pdf.
Printer vrijgegeven.
oefeningen.pdf geprint.
Printer vrijgegeven.
Op naar huis.
Uitvoer B
samenvatting.pdf geprint.
Unhandled exception. System.Exception: notities.docx is geen pdf.
at ...
Uitvoer C
samenvatting.pdf geprint.
notities.docx is geen pdf.
Printer vrijgegeven.
Op naar huis.
- Welke uitvoer hoort bij welke versie? Beslis eerst op papier, en probeer het daarna uit.
- Waarom wordt
oefeningen.pdfin uitvoer C niet geprint? - Welke versie kies je als je zoveel mogelijk wil printen?
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
throwspringt naar de eerstecatchdie klaarstaat, ook als die inMainstaat en niet in de methode zelf. finallyloopt altijd, met of zonder exception. Zie finally: het derde lid.- Een
tryrond de lus stopt bij de eerste fout, eentryin de lus slaat enkel dat ene element over. Zie Rond afzonderlijke elementen in de loop.
Bankmanager 2: terugbetalen na de citytrip
Lotte en Mo zijn net terug van een citytrip naar Berlijn. Ze hebben om beurt voor elkaar betaald en betalen elkaar nu terug, elk vanaf een nieuwe studentenrekening. Je werkt verder met de klasse Rekening uit BankManager (deel 2, met de Staat). Beide nieuwe methoden staan in Program.cs.
Deel 1. Schrijf static Rekening CreeerStudentenRekening(string klantNaam, string rekeningNummer). Ze maakt een nieuwe rekening, vult naam en nummer in en geeft ze terug. Een studentenrekening start met 50 euro. Balans heeft een private set, dus die 50 euro komt er via StortGeld.
Testcode deel 1. Zet deze code in je Main.
Rekening lotte = CreeerStudentenRekening("Lotte", "BE02 2000");
Rekening mo = CreeerStudentenRekening("Mo", "BE03 3000");
lotte.ToonInfo();
mo.ToonInfo();
lotte.StortGeld(mo.HaalGeldAf(20));
lotte.ToonInfo();
mo.ToonInfo();Lotte (BE02 2000): 50 euro, Geldig
Mo (BE03 3000): 50 euro, Geldig
Lotte (BE02 2000): 70 euro, Geldig
Mo (BE03 3000): 30 euro, Geldig
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. Schrijf static void SimuleerOverdracht(Rekening r1, Rekening r2, Random generator). Vijf keer na elkaar:
- kies een willekeurig bedrag van 1 tot en met 100 euro;
- toon wie hoeveel terugbetaalt aan wie;
- haal het bedrag af bij de verzender en stort wat er afgehaald werd bij de ontvanger;
- wissel daarna de rollen om: eerst betaalt
r1aanr2, danr2aanr1, enzovoort.
Main toont hoeveel geld ze samen hebben, laat de overdrachten gebeuren, toont beide rekeningen en daarna opnieuw het totaal. Voer het programma een paar keer uit. Bijvoorbeeld:
Samen voor de citytrip: 100 euro
Lotte betaalt 25 euro terug aan Mo.
Mo betaalt 12 euro terug aan Lotte.
Lotte betaalt 47 euro terug aan Mo.
Rekening leeg nu
Mo betaalt 78 euro terug aan Lotte.
Gaat niet. Rekening geblokkeerd.
Lotte betaalt 66 euro terug aan Mo.
Gaat niet. Rekening geblokkeerd.
Ongeldig bedrag.
Lotte (BE02 2000): 0 euro, Geblokkeerd
Mo (BE03 3000): 22 euro, Geldig
Samen na de citytrip: 22 euro
Ze betalen elkaar enkel terug, dus samen hebben ze na afloop nog altijd 100 euro. Toch? Zoek uit waar het geld naartoe gaat, en waar Ongeldig bedrag. vandaan komt. Pas SimuleerOverdracht dan aan zodat er geen geld meer verdwijnt.
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.
SimuleerOverdrachtkrijgt de adressen van de twee rekeningen. Wat ze eraan verandert, zie je achteraf inMain.Rekening verzender = r1;kopieert enkel een referentie. Zo wissel je de rollen om zonder een rekening te kopiëren.- Elke methode van
Rekeningwerkte correct, en toch verdween er geld:StortGeld(HaalGeldAf(...))haalt eerst af en controleert pas daarna of de ontvanger iets mag krijgen. Een controle op het totaal vindt zo’n fout.
Project: SpaceCommand (Final Essentials)
Een Final Essentials oefening is een opgave waarin alle leerstof van de voorbije oefeningen aan bod komt.
Je bent de software-architect van de Aardse Vloot. Je schrijft een systeem om ruimteschepen te beheren, op te waarderen en tegen elkaar te laten oefenen. Objecten doorgeven en teruggeven, referenties, null en exceptions: alles van dit hoofdstuk komt terug.
Deel 1: de klasse RuimteSchip
| Property of methode | Type | Werking |
|---|---|---|
Naam |
string |
Auto-property. |
Kapitein |
string |
Auto-property met private set, beginwaarde "Onbekend". |
WisselKapitein(string nieuweKapitein) |
void |
Enige manier om de kapitein te veranderen. |
RompSterkte, SchildKracht, VuurKracht |
int |
Auto-properties, van 0 tot 100. |
Ervaring |
int |
Auto-property met private set, start op 0. |
Schade |
int |
Auto-property met private set, start op 0. |
IsKapot |
bool |
Read-only: true als Schade groter dan of gelijk aan RompSterkte is. |
TotaleKracht |
double |
Read-only: VuurKracht * Ervaring + SchildKracht * 0.5. |
TrainBemanning() |
void |
Verhoogt Ervaring met 1. |
LoopSchadeOp(int punten) |
void |
Verhoogt Schade met punten. |
Onderhoud() |
void |
Zet Schade op 0 en toont Schip [Naam] is volledig hersteld. |
ToonRapport() |
void |
Toont naam, kapitein, stats, ervaring, schade, kracht en of het schip kapot is (zie het voorbeeld). |
Deel 2: de vlootmanager (Program.cs)
static RuimteSchip MaakWillekeurigSchip(string naam, Random generator)maakt een schip met die naam en geeft het terug.RompSterkte,SchildKrachtenVuurKrachtkrijgen elk een willekeurige waarde van 10 tot en met 100.static RuimteSchip SimuleerGevecht(RuimteSchip s1, RuimteSchip s2):- Is een van beide schepen
null, dan werpt de methode eenExceptionop:Een gevecht heeft twee schepen nodig. - Is een van beide schepen kapot, dan werpt ze een
Exceptionop:[Naam] is kapot en moet eerst in onderhoud. - Het schip met de laagste
TotaleKrachtverliest. Toon wie wint, met de kracht van beide schepen. Daarna loopt de verliezer 20 schade op en traint de winnaar zijn bemanning. - De methode geeft de verliezer terug. Zijn beide even sterk, dan is het gelijkspel: toon dat, er verandert niets, en de methode geeft
nullterug.
- Is een van beide schepen
static void PimpMijnSchip(RuimteSchip schip)zetVuurKrachtenSchildKrachtvan het schip op 100.
Deel 3: het scenario (Main)
- Maak met één
Randomtwee schepen: “De Voyager” en “De Millennium Falcon”. - Geef ze een kapitein: Janeway en Solo.
- Toon beide rapporten.
- Laat ze vechten en toon de rapporten opnieuw. Zie je de schade en de ervaring?
- Was er een verliezer, stuur die dan naar de garage (
PimpMijnSchip), toon zijn rapport en laat ze nog eens vechten. Wint de verliezer nu? Waarom (niet)? - Schrijf
RuimteSchip s3 = s1;en geefs3een andere naam, bv. “De Enterprise”. Toon het rapport vans1. Wat merk je? Teken de stack en de heap. - Roep
SimuleerGevecht(s1, null)op in eentryen toone.Message. - Laat ze nog vijf keer vechten, in een lus. Wordt een schip kapot, dan moet de lus gewoon verder kunnen en toont ze de melding. Waar zet je de
try? - Stuur na de lus beide schepen in onderhoud en toon hun rapport.
Bijvoorbeeld (bij jou komen er andere getallen uit):
De Voyager (kapitein Janeway): romp 84, schild 100, vuur 61
ervaring 0, schade 0, kracht 50, kapot: False
De Millennium Falcon (kapitein Solo): romp 47, schild 11, vuur 14
ervaring 0, schade 0, kracht 5,5, kapot: False
De Voyager (50) verslaat De Millennium Falcon (5,5).
De Voyager (kapitein Janeway): romp 84, schild 100, vuur 61
ervaring 1, schade 0, kracht 111, kapot: False
De Millennium Falcon (kapitein Solo): romp 47, schild 11, vuur 14
ervaring 0, schade 20, kracht 5,5, kapot: False
De Millennium Falcon (kapitein Solo): romp 47, schild 100, vuur 100
ervaring 0, schade 20, kracht 50, kapot: False
De Voyager (111) verslaat De Millennium Falcon (50).
De Enterprise (kapitein Janeway): romp 84, schild 100, vuur 61
ervaring 2, schade 0, kracht 172, kapot: False
Fout: Een gevecht heeft twee schepen nodig.
De Enterprise (172) verslaat De Millennium Falcon (50).
Fout: De Millennium Falcon is kapot en moet eerst in onderhoud.
Fout: De Millennium Falcon is kapot en moet eerst in onderhoud.
Fout: De Millennium Falcon is kapot en moet eerst in onderhoud.
Fout: De Millennium Falcon is kapot en moet eerst in onderhoud.
Schip De Enterprise is volledig hersteld.
Schip De Millennium Falcon is volledig hersteld.
De Enterprise (kapitein Janeway): romp 84, schild 100, vuur 61
ervaring 3, schade 0, kracht 233, kapot: False
De Millennium Falcon (kapitein Solo): romp 47, schild 100, vuur 100
ervaring 0, schade 0, kracht 50, kapot: False
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.
PimpMijnSchipenSimuleerGevechtkrijgen het adres van een schip: wat ze veranderen, zie je inMain.MaakWillekeurigSchipenSimuleerGevechtgeven een schip terug,SimuleerGevechtooknullbij gelijkspel.s3 = s1maakt geen tweede schip.SimuleerGevechtweigert met een exception wat niet kan,Mainvangt ze op. Zo kan een gevecht nooit stilletjes met een kapot schip doorgaan.- De formule bepaalt wie wint, niet je verwachting. Twijfel je, reken het na met de getallen uit het rapport.