ToStringoverschrijf je met preciespublic override string ToString(). Ze geeft tekst terug en toont zelf niets:Console.WriteLine(mijnObject)en$"{mijnObject}"roepen ze voor jou op (uitleg).- Overschrijf je
Equals, overschrijf dan ookGetHashCode, metHashCode.Combine(...)en dezelfde properties. Anders waarschuwt de compiler metCS0659, en vindt eenDictionaryje object niet terug (uitleg). - Begin
Equalsmet de testif (o is not Boek temp), die danfalseteruggeeft, zoals in het boek (uitleg). Hoeiswerkt, zie je in hoofdstuk 16. De groene kronkelCS8765onder de parameter mag je laten staan. - Een
abstractmethode heeft geen body, en elke child moet ze overriden. Staat er één in je klasse, dan moet de klasse zelf ookabstractzijn (uitleg).
Nu je met overerving werkt, is het tijd om de ingebouwde “Class designer” van Visual Studio eens te bekijken: die tekent je klassen en hun overerving als schema. Deze kennisclip toont hoe je hem installeert en gebruikt: Class diagram en de class designer in Visual Studio.
Voorspel de uitvoer: wie woont er op kot? (Essential)
Je project heet Kot. Er zijn vier klassen, elk in een eigen bestand:
internal class Koelkast
{
public int AantalBlikjes { get; set; }
}internal class Kotgenoot
{
public string Naam { get; set; }
public string ToString()
{
return $"Kotgenoot {Naam}";
}
}internal class Afwasbeurt
{
public string Wie { get; set; }
public override string ToString()
{
Console.WriteLine($"{Wie} wast af");
return "";
}
}internal class Pizza
{
public string Smaak { get; set; }
public override string ToString()
{
return $"Pizza {Smaak}";
}
public override bool Equals(object o)
{
if (o is not Pizza temp)
return false;
return Smaak == temp.Smaak;
}
public override int GetHashCode()
{
return HashCode.Combine(Smaak);
}
}Deel 1. Schrijf op papier wat dit programma toont, lijn per lijn. Typ de code pas daarna over en vergelijk.
Twee dingen die je daarbij nodig hebt: niet enkel Console.WriteLine(object) roept ToString op, ook een object tussen accolades in $"..." doet dat. En C# stelt de volledige tekst tussen de haakjes van WriteLine eerst samen, en toont hem pas daarna.
Koelkast frigo = new Koelkast() { AantalBlikjes = 6 };
Console.WriteLine(frigo);
Console.WriteLine(frigo.GetType().Name);
Console.WriteLine("---");
Kotgenoot jonas = new Kotgenoot() { Naam = "Jonas" };
Console.WriteLine(jonas);
Console.WriteLine(jonas.ToString());
Console.WriteLine("---");
Afwasbeurt vandaag = new Afwasbeurt() { Wie = "Lotte" };
Console.WriteLine($"Planning: {vandaag}!");
Console.WriteLine("---");
Pizza mijne = new Pizza() { Smaak = "margherita" };
Pizza jouwe = new Pizza() { Smaak = "margherita" };
Pizza gedeeld = mijne;
Console.WriteLine(mijne == jouwe);
Console.WriteLine(mijne.Equals(jouwe));
Console.WriteLine(ReferenceEquals(mijne, jouwe));
Console.WriteLine(ReferenceEquals(mijne, gedeeld));
Console.WriteLine(mijne.Equals(frigo));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. Behalve CS8618 en CS8765, die je mag laten staan, geeft de compiler nog één waarschuwing. Welke, en bij welke klasse? Herstel ze. Wat toont de vierde regel van de uitvoer 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 3. Herstel Afwasbeurt, zodat het programma Planning: Lotte wast af! toont.
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.
Console.WriteLine(object)en$"{object}"roepen zelfToString()op. Zonderoverridegebruiken ze de versie vanSystem.Object, ook als je klasse een methode met dezelfde naam heeft.ToStringgeeft tekst terug. Wie erinConsole.WriteLineschrijft, krijgt de tekst op de verkeerde plaats.==vergelijkt bij je eigen klassen de referenties,Equalsvergelijkt wat jij beslist. Zie System.Object en ReferenceEquals().
Extra ToString aan bestaande projecten
Twee klassen die je al hebt, krijgen een ToString. Kopieer de klassen naar een nieuw project, dan hoef je je oude Main niet mee te nemen.
Deel 1: Pokémon. In de Pokémontester van hoofdstuk 10 gaf je je Pokemon-klasse een methode ShowInfo() die vier regels toont. Overschrijf ToString in Pokemon, zodat Console.WriteLine(pikachu); exact dezelfde vier regels toont. Gebruik \n om naar een nieuwe regel te gaan. ShowInfo() mag blijven, maar wordt één regel: ze roept ToString() op.
Waarom toont ShowInfo zelf iets, terwijl ToString niets toont?
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: Bookmark. Neem de klasse BookMark uit de Bookmark Manager van hoofdstuk 12 en HiddenBookMark uit HiddenBookmark van hoofdstuk 13. Overschrijf ToString in allebei:
- een
BookMarktoont zijn naam, gevolgd door de URL tussen haakjes; - een
HiddenBookMarktoont hetzelfde, met daarachter een spatie en---HIDDEN---.
Er mag geen dubbele code in HiddenBookMark staan. Tip: base.ToString().
Testcode. Zet deze code in je Main. Je code werkt als je exact deze uitvoer krijgt.
BookMark google = new BookMark() { Naam = "Google", URL = "https://www.google.com" };
HiddenBookMark reddit = new HiddenBookMark() { Naam = "Reddit", URL = "https://www.reddit.com" };
Console.WriteLine(google);
Console.WriteLine(reddit);Google (https://www.google.com)
Reddit (https://www.reddit.com) ---HIDDEN---
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 nog wil. Pas ToonLijst in je Bookmark Manager aan: elke site verschijnt met haar nummer en daarna haar ToString, bijvoorbeeld 1. Google (https://www.google.com). Wat zie je bij een verborgen site?
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.
ToStringgeeft tekst terug. Wil je ze tonen, dan doe je dat buiten de methode.- Met
base.ToString()staat de tekst van de parent op één plaats. VerandertBookMarkooit, dan verandertHiddenBookMarkvanzelf mee. - Zie ToString() overriden.
Boek: de tweedehandsboekenbeurs (Essential)
Elk jaar verkoopt je studentenvereniging tweedehandse boeken: cursusboeken van vorig jaar, maar ook een roman of een fotoboek. Jij schrijft de klassen.
Deel 1. Maak een klasse Boek met:
- drie auto-properties:
ISBN(long),TitelenAuteur(allebeistring); - een full property
Prijs(double), met een private instantievariabeleprijs.
Maak twee child-klassen die van Boek erven:
TekstBoek, een cursusboek, met een extra propertyStudiejaar(int);KoffietafelBoek, zonder extra properties.
Elk soort boek heeft zijn eigen prijsgrenzen. Een TekstBoek kost tussen 20 en 80 euro, een KoffietafelBoek tussen 35 en 100 euro. Overschrijf daarvoor in beide child-klassen de property Prijs:
- maak
PrijsvirtualinBoek; - in de child schrijf je
public override double Prijs. Degetgeeftbase.Prijsterug. Desetcontroleert de waarde en doet daarnabase.Prijs = value;; - ligt de prijs buiten de grenzen, dan werpt de
seteen exception op:throw new ArgumentException("Een cursusboek kost tussen 20 en 80 euro.");, of"Een koffietafelboek kost tussen 35 en 100 euro.". De prijs verandert dan niet.
Overschrijf ToString in Boek, zodat een boek zich zo toont: Titel - Auteur (ISBN) - Prijs euro.
Deel 2. Twee boeken kunnen samen verkocht worden als omnibus. Schrijf in Boek een static methode TelOp die twee Boek-objecten als parameter krijgt en een nieuw Boek teruggeeft:
- de titel is
Omnibus:gevolgd door de twee titels, met+ertussen; - de auteur is de twee auteurs, gescheiden door een komma en een spatie;
- de prijs is de som van beide prijzen, gedeeld door 2;
- het ISBN blijft 0: een omnibus krijgt pas een ISBN als hij gedrukt wordt.
Een omnibus is een gewoon Boek, geen TekstBoek of KoffietafelBoek. De prijsgrenzen gelden voor hem dus niet.
Testcode. Zet deze code in je Main. Je code werkt als je exact deze uitvoer krijgt.
Boek roman = new Boek() { ISBN = 9789000000011, Titel = "Het Kot", Auteur = "Lies Peeters", Prijs = 15 };
TekstBoek cursus = new TekstBoek() { ISBN = 9781234567897, Titel = "Programmeren in C#", Auteur = "Jan Janssens", Studiejaar = 1, Prijs = 30 };
KoffietafelBoek fotoboek = new KoffietafelBoek() { ISBN = 9789000000028, Titel = "Antwerpen van boven", Auteur = "Mo Benali", Prijs = 45 };
Console.WriteLine(roman);
Console.WriteLine(cursus);
Console.WriteLine(fotoboek);
Console.WriteLine(Boek.TelOp(roman, fotoboek));
try
{
cursus.Prijs = 10;
}
catch (ArgumentException e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine(cursus);
try
{
fotoboek.Prijs = 150;
}
catch (ArgumentException e)
{
Console.WriteLine(e.Message);
}Het Kot - Lies Peeters (9789000000011) - 15 euro
Programmeren in C# - Jan Janssens (9781234567897) - 30 euro
Antwerpen van boven - Mo Benali (9789000000028) - 45 euro
Omnibus: Het Kot + Antwerpen van boven - Lies Peeters, Mo Benali (0) - 30 euro
Een cursusboek kost tussen 20 en 80 euro.
Programmeren in C# - Jan Janssens (9781234567897) - 30 euro
Een koffietafelboek kost tussen 35 en 100 euro.
PRO: in de appendix lees je hoe je de +-operator zelf kan schrijven, zodat roman + fotoboek een omnibus geeft.
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.
- Ook een property kan je overschrijven. Met
base.Prijsblijft de prijs in de private instantievariabele vanBoekstaan, en voegt de child enkel een controle toe. - Een
setdie een foute waarde stil negeert, verbergt een bug. Metthrowmerkt wie de klasse gebruikt meteen dat er iets mis is. Zie Zelf exceptions maken. - Een
longtoont geen voorloopnullen: een ISBN dat met 0 begint, verliest die nul.
De boekenbeurs telt (Essential)
Op de boekenbeurs brengen Lotte en Jonas allebei hun cursus “Programmeren in C#” binnen: hetzelfde ISBN, maar een andere prijs. Voor de beurs is dat hetzelfde boek, twee keer. Werk verder met de klassen uit Boek: de tweedehandsboekenbeurs.
Deel 1. Twee boeken zijn gelijk als hun ISBN gelijk is. Overschrijf Equals in Boek. Begin zoals in het boek met de test if (o is not Boek temp), die dan false teruggeeft. Schrijf nog geen GetHashCode, ook al zegt het blok bovenaan deze pagina dat het hoort: in deel 2 zie je waarom.
Testcode. Je code werkt als je exact deze uitvoer krijgt.
TekstBoek vanLotte = new TekstBoek() { ISBN = 9781234567897, Titel = "Programmeren in C#", Auteur = "Jan Janssens", Studiejaar = 1, Prijs = 30 };
TekstBoek vanJonas = new TekstBoek() { ISBN = 9781234567897, Titel = "Programmeren in C#", Auteur = "Jan Janssens", Studiejaar = 1, Prijs = 25 };
KoffietafelBoek vanMira = new KoffietafelBoek() { ISBN = 9789000000028, Titel = "Antwerpen van boven", Auteur = "Mo Benali", Prijs = 45 };
Console.WriteLine(vanLotte == vanJonas);
Console.WriteLine(vanLotte.Equals(vanJonas));
Console.WriteLine(vanLotte.Equals(vanMira));False
True
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.
Deel 2. De beurs houdt bij hoeveel exemplaren er van elk boek liggen, in een Dictionary<Boek, int>: de sleutel is het boek, de waarde het aantal exemplaren. Voeg deze code toe aan je Main. ContainsKey zegt of een sleutel al in de Dictionary zit.
Boek[] binnengebracht = { vanLotte, vanMira, vanJonas };
Dictionary<Boek, int> voorraad = new Dictionary<Boek, int>();
foreach (Boek boek in binnengebracht)
{
if (voorraad.ContainsKey(boek))
{
voorraad[boek]++;
}
else
{
voorraad.Add(boek, 1);
}
}
foreach (var item in voorraad)
{
Console.WriteLine($"{item.Value} x {item.Key.Titel}");
}Je verwacht 2 x Programmeren in C#. Wat toont het programma? Welke waarschuwing gaf de compiler al bij Boek? Herstel Boek, zodat de voorraad klopt.
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.
- Wie
Equalsoverschrijft, overschrijft ookGetHashCode, met dezelfde properties. Twee gelijke objecten moeten dezelfde hashcode hebben. - De fout zie je pas als een
Dictionaryje object als sleutel gebruikt. De waarschuwingCS0659zag het al eerder: lees je waarschuwingen. - Zie Equals() overriden en GetHashCode() overriden.
Geometrische figuren (Essential)
Een “geometrische figuur” kan je niet tekenen, een rechthoek wel. Dat is het voorbeeld waarmee het boek abstracte klassen uitlegt.
Maak een abstracte klasse GeometrischeFiguur met:
- twee properties
HoogteenBreedte(int), met eenprivate set; - een constructor met twee parameters: eerst de hoogte, dan de breedte. Ook een abstracte klasse mag een constructor hebben. Met
newkan je hem niet oproepen, maar een child roept hem op metbase(...), zoals in hoofdstuk 13; - een abstracte methode
BerekenOppervlakte()die eendoubleteruggeeft; - een read-only property
Oppervlakte, waarvan degethet resultaat vanBerekenOppervlakte()teruggeeft; - een abstracte read-only property
AantalHoeken(int); - een override van
ToString, die de naam van de klasse, de breedte, de hoogte, het aantal hoeken en de oppervlakte toont, zoals in de testcode hieronder. De naam van de klasse vraag je op metGetType().Name.
Oppervlakte heeft enkel een get. Met een set kon iemand de oppervlakte aanpassen zonder de hoogte of de breedte te veranderen, en dan klopt ze niet meer.
Maak drie klassen:
Rechthoekerft vanGeometrischeFiguur. De oppervlakte is breedte maal hoogte, en een rechthoek heeft 4 hoeken.Vierkanterft vanRechthoek. Het heeft één constructor, met enkel de lengte van een zijde.Vierkantberekent zelf niets: de oppervlakte en het aantal hoeken erft het vanRechthoek.Driehoekerft vanGeometrischeFiguur. De oppervlakte is breedte maal hoogte gedeeld door2.0, en een driehoek heeft 3 hoeken.
Herinner je de strikvraag over Vierkant en Rechthoek in Is een of heeft een? Hier mag het wel: hoogte en breedte hebben een private set, dus na het aanmaken kan een vierkant niet meer van vorm veranderen.
Testcode. Je code werkt als je exact deze uitvoer krijgt.
List<GeometrischeFiguur> figuren = new List<GeometrischeFiguur>();
figuren.Add(new Rechthoek(3, 4));
figuren.Add(new Vierkant(4));
figuren.Add(new Driehoek(3, 5));
double totaal = 0;
foreach (GeometrischeFiguur figuur in figuren)
{
Console.WriteLine(figuur);
totaal += figuur.Oppervlakte;
}
Console.WriteLine($"Samen: {totaal}");Rechthoek van 4 op 3: 4 hoeken, oppervlakte 12
Vierkant van 4 op 4: 4 hoeken, oppervlakte 16
Driehoek van 5 op 3: 3 hoeken, oppervlakte 7,5
Samen: 35,5
Rechthoek van 4 op 3 betekent: 4 breed en 3 hoog.
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 abstracte klasse mag gewone code bevatten, zoals
OppervlakteenToString, die abstracte leden gebruikt. Elke child vult enkel de gaten in. - Ook een property kan abstract zijn:
public abstract int AantalHoeken { get; }heeft geen body, en de child moet ze overriden. Zie Abstracte properties. GetType().Namegeeft de naam van de echte klasse van het object, ook als de code in de parent staat. Zie GetType().
Stevens abstracte bouwwerf (Essential)
Stagiair Steven schrijft een programma voor een bouwbedrijf. Hij liet een A.I. de klassen maken en plakte alles in zijn project zonder het na te lezen. Niets compileert. Om plaats te sparen staan de klassen van een fragment hier onder elkaar. In je eigen project zet je elke klasse in een apart bestand.
Fragment 1.
internal abstract class Bouwmachine
{
public int Gewicht { get; set; }
}
internal class Graafmachine : Bouwmachine
{
public int Bakinhoud { get; set; }
}
// in Main
Bouwmachine machine = new Bouwmachine();
machine.Gewicht = 12000;Fragment 2.
internal abstract class Materiaal
{
public double Hoeveelheid { get; set; }
public abstract double BerekenPrijs()
{
return 0;
}
}
internal class Zand : Materiaal
{
public override double BerekenPrijs()
{
return Hoeveelheid * 45;
}
}Fragment 3.
internal class Werknemer
{
public int Uren { get; set; }
public abstract double BerekenLoon();
}
internal class Metser : Werknemer
{
public override double BerekenLoon()
{
return Uren * 32.5;
}
}Fragment 4.
internal abstract class Gebouw
{
public int Verdiepingen { get; set; }
public abstract int BerekenBouwtijd();
}
internal class Rijwoning : Gebouw
{
public int BerekenBouwTijd()
{
return Verdiepingen * 8;
}
}Fragment 5.
internal sealed class Werfkeet
{
public int Zitplaatsen { get; set; }
}
internal class LuxeWerfkeet : Werfkeet
{
public bool HeeftDouche { get; set; }
}Deel 1. Steven zette elk fragment in een apart project. Dit zijn de vijf meldingen die hij kreeg, door elkaar:
- A.
CS0534 'Rijwoning' does not implement inherited abstract member 'Gebouw.BerekenBouwtijd()' - B.
CS0509 'LuxeWerfkeet': cannot derive from sealed type 'Werfkeet' - C.
CS0144 Cannot create an instance of the abstract type or interface 'Bouwmachine' - D.
CS0513 'Werknemer.BerekenLoon()' is abstract but it is contained in non-abstract type 'Werknemer' - E.
CS0500 'Materiaal.BerekenPrijs()' cannot declare a body because it is marked abstract
Koppel elke melding aan een fragment. Zoek daarna in dat fragment de lijn die het probleem veroorzaakt, en zeg in je eigen woorden welke regel Steven brak. Doe het op papier, zonder Visual Studio.
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. Herstel elk fragment met zo weinig mogelijk aanpassingen, zodat het compileert en doet wat Steven bedoelde. Test elk fragment in een eigen project.
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 nog wil. Stevens namespace heet Bouwwerf, dus kraan.GetType() toont Bouwwerf.Kraan. Steven wil Kraan van 40 meter op het scherm. De A.I. stelde dit voor:
internal class Kraan
{
public int Hoogte { get; set; }
public override string GetType()
{
return "Kraan";
}
}
// in Main
Kraan kraan = new Kraan();
kraan.Hoogte = 40;
Console.WriteLine($"{kraan.GetType()} van {kraan.Hoogte} meter");Waarom compileert dit niet? Hoe krijgt Steven wel Kraan van 40 meter op het scherm?
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.
- Elke melding noemt tussen aanhalingstekens de klasse of methode waar het misloopt. Daar begin je te zoeken, maar de fout staat niet altijd op die plek: CS0534 wijst naar
Rijwoning, en het probleem was één hoofdletter in de naam van de methode. - Zet je de vijf fragmenten samen in één project, dan meldt de compiler er maar vier. CS0144 verschijnt pas als de andere vier opgelost zijn. Krijg je na een herstelling een nieuwe melding, dan zat die fout er dus al.
- Zie Abstracte klassen in C#, Abstracte methoden, sealed en GetType().
Money, money, money (Essential)
Maak enkele klassen die een bank kan gebruiken:
- Een abstracte klasse
Rekening. Het saldo staat in een private instantievariabele, die je enkel via een read-only propertySaldokan uitlezen. Twee methoden passen het saldo aan:VoegGeldToe(double bedrag)enHaalGeldAf(double bedrag).HaalGeldAfgeeft eenboolterug:falseals er niet genoeg geld op de rekening staat (dan verandert het saldo niet), anderstrue. Verder is er een abstracte methodeBerekenRente()die de rente alsdoubleteruggeeft. - Een klasse
BankRekeningdie eenRekeningis. De rente van eenBankRekeningis 5% als het saldo hoger is dan 100 euro, anders 0. - Een klasse
SpaarRekeningdie eenRekeningis. De rente van eenSpaarRekeningis altijd 2%. - Een klasse
ProRekeningdie eenSpaarRekeningis. Ze berekent de rente zoals eenSpaarRekening(base.BerekenRente()), en telt er per volle 1000 euro saldo nog 10 euro bij. Bij 2500 euro is dat 50 + 20 = 70 euro.
Testcode. Je code werkt als je exact deze uitvoer krijgt.
BankRekening bank = new BankRekening();
bank.VoegGeldToe(80);
Console.WriteLine($"BankRekening met {bank.Saldo} euro: rente {bank.BerekenRente()} euro");
bank.VoegGeldToe(120);
Console.WriteLine($"BankRekening met {bank.Saldo} euro: rente {bank.BerekenRente()} euro");
SpaarRekening spaar = new SpaarRekening();
spaar.VoegGeldToe(500);
Console.WriteLine($"SpaarRekening met {spaar.Saldo} euro: rente {spaar.BerekenRente()} euro");
ProRekening pro = new ProRekening();
pro.VoegGeldToe(2500);
Console.WriteLine($"ProRekening met {pro.Saldo} euro: rente {pro.BerekenRente()} euro");
if (!pro.HaalGeldAf(3000))
{
Console.WriteLine("Zoveel geld staat er niet op de ProRekening.");
}BankRekening met 80 euro: rente 0 euro
BankRekening met 200 euro: rente 10 euro
SpaarRekening met 500 euro: rente 10 euro
ProRekening met 2500 euro: rente 70 euro
Zoveel geld staat er niet op de ProRekening.
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.
Rekeningregelt wat elke rekening heeft: het saldo en de twee methoden. Wat per soort verschilt, de rente, isabstract: elke child moet het invullen.ProRekeningerft vanSpaarRekening, niet vanRekening. Zo haaltbase.BerekenRente()de 2% op, en staat die berekening maar één keer in je code.- Zie Abstracte methoden.
Saldo tekort (Essential)
Het is de 28e van de maand. Je wil 80 euro afhalen voor het weekend, maar er staat nog maar 50 euro op je rekening. Nu geeft HaalGeldAf uit Money, money, money gewoon false terug, en wie dat vergeet te controleren, merkt niets. Een eigen exception zegt het luider.
Deel 1. Maak een klasse SaldoTekortException die erft van Exception, met de drie standaardconstructors uit het boek (Een eigen exception ontwerpen).
Pas daarna HaalGeldAf in Rekening aan: ze wordt void. Staat er niet genoeg geld op de rekening, dan werpt ze een SaldoTekortException op met de boodschap Onvoldoende saldo: je komt ... euro tekort.. Het saldo verandert dan niet.
Testcode. De testcode van Money, money, money compileert nu niet meer, want HaalGeldAf geeft niets meer terug. Vervang ze door deze code. Je code werkt als je exact deze uitvoer krijgt.
SpaarRekening rekening = new SpaarRekening();
rekening.VoegGeldToe(50);
try
{
rekening.HaalGeldAf(80);
}
catch (SaldoTekortException e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine($"Saldo: {rekening.Saldo} euro");Onvoldoende saldo: je komt 30 euro tekort.
Saldo: 50 euro
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. Haal in de tweede constructor : base(message) weg, zodat er public SaldoTekortException(string message) { } staat. Het compileert nog. Voer de testcode uit. Wat toont ze nu, 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 eigen exception is een gewone klasse die van
Exceptionerft. De naam zegt al wat er misliep. - De boodschap geef je door aan de parent met
: base(message), net als bij elke andere constructor die iets van zijn parent nodig heeft. - Met
catch (SaldoTekortException e)vang je enkel die ene fout op. Zie Zelf exceptions maken.
Dierentuin (Essential)
Maak een console-applicatie met een abstracte klasse Dier. Elk dier heeft een gewicht (int) en een abstracte methode void Zegt() die het geluid van dat dier op het scherm toont. Maak enkele child-klassen die van Dier erven en Zegt overriden, bijvoorbeeld Koe, Slang en Varken. Die drie heb je nodig in Dierentuin advanced, in hoofdstuk 16.

Zet enkele dieren in een List<Dier>. Daarna verschijnt een menu dat blijft terugkomen tot de gebruiker q kiest:
- Dier verwijderen: de gebruiker geeft in het hoeveelste dier uit de lijst weg moet.
- Gemiddeld gewicht: het gemiddelde gewicht van alle dieren, met twee cijfers na de komma.
- Dieren praten: van elk dier wordt
Zegt()opgeroepen. - Opnieuw beginnen: de lijst wordt leeggemaakt en opnieuw gevuld met de dieren van bij de start.
Schrijf voor de menu-items 1, 2 en 3 een methode, met de lijst als parameter. Ook het vullen van de lijst komt in een methode, want je hebt het twee keer nodig: bij de start en bij “opnieuw beginnen”.
Een lege lijst mag je programma niet laten crashen: kies je dan 1 of 2, dan toont het programma Er zijn geen dieren meer. Een nummer dat niet in de lijst staat, geeft Dat dier bestaat niet. Je mag ervan uitgaan dat de gebruiker een getal typt.
Een voorbeeld, met een koe van 600 kg, een slang van 3 kg en een varken van 110 kg:
1. Dier verwijderen
2. Gemiddeld gewicht
3. Dieren praten
4. Opnieuw beginnen
q. Stoppen
>3
Moeeeh
Sssssss
Knor knor
...
>2
Gemiddeld gewicht: 237,67 kg
...
>1
Het hoeveelste dier moet weg (1 tot en met 3)?
>2
...
>3
Moeeeh
Knor knor
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.
- Van
Dierkan je geen object maken, maar eenList<Dier>kan wel koeien, slangen en varkens bevatten.dier.Zegt()laat bij elk dier zijn eigen geluid horen. Waarom dat werkt, zie je in hoofdstuk 16. - Omdat
Zegtabstractis, kan geen enkele child vergeten een geluid te maken. - Het vullen van de lijst staat in een methode, want je hebt het twee keer nodig.
Meme Lord Simulator (Final Essentials) (GPT)
Het internet is wild en jij bent de curator. Bouw een systeem dat de virale waarde van verschillende soorten memes berekent.
Deel 1: de abstracte klasse. Maak een abstracte klasse Meme met:
- drie properties:
Auteur(string), de maker van de meme;Beschrijving(string), wat er op de afbeelding staat; enBasisLikes(int), het aantal likes dat ze standaard krijgt; - een abstracte methode
BerekenMemeWaarde()die eendoubleteruggeeft; - een
virtualread-only propertyIsCringe(bool). Standaard is een meme cringe alsBasisLikeskleiner is dan 100; - een override van
ToStringdie[Auteur] post: [Beschrijving] - Waarde: [waarde] - Status: [status]toont. De status isCringeals de meme cringe is, andersDank.
Deel 2: de soorten. Maak drie klassen die van Meme erven:
DankMeme(hoge kwaliteit, niche humor) heeft een extra propertyIronieNiveau(int, van 1 tot 10). De waarde isBasisLikesmaalIronieNiveau. Een dank meme is nooit cringe, tenzij het ironieniveau kleiner is dan 3.NormieMeme(Minion-quotes, 9gag-reposts) isBasisLikesmaal 0,5 waard, en is altijd cringe.DeepFriedMeme(onleesbaar, luid en vervormd) heeft een extra propertyRuisfactor(int, van 1 tot 100). De waarde isBasisLikesplusRuisfactormaal 10. ZijnToStringzet de volledige tekst van deToStringvanMemein hoofdletters en plakt er🔥💀🅱️achter.
De grenzen van IronieNiveau en Ruisfactor hoef je niet te controleren.
Zonder Console.OutputEncoding = System.Text.Encoding.UTF8; bovenaan je Main toont de console vraagtekens in plaats van de emoji.
Deel 3: de feed. Geef de klasse Meme een static methode GenereerFeed(List<Meme> memes). Ze overloopt de lijst:
- een cringe meme toont ze als
Cringe verwijderd:gevolgd door de meme. Ze haalt hem niet uit de lijst: “verwijderd” betekent enkel dat hij niet in de feed komt; - elke andere meme toont ze gewoon;
- op het einde toont ze
Gemiddelde waarde van de feed:, het gemiddelde van de memes die niet cringe waren. Was elke meme cringe, dan toont zeGeen enkele meme overleefde de feed.
Maak in Main een lijst met memes van alle soorten, met wat cringe ertussen, en roep Meme.GenereerFeed op. Met deze memes:
memes.Add(new DankMeme() { Auteur = "Tim", Beschrijving = "Kat met zonnebril", BasisLikes = 40, IronieNiveau = 8 });
memes.Add(new NormieMeme() { Auteur = "Lies", Beschrijving = "Minion op maandag", BasisLikes = 2000 });
memes.Add(new DankMeme() { Auteur = "Jonas", Beschrijving = "Examenrooster als horrorfilm", BasisLikes = 300, IronieNiveau = 2 });
memes.Add(new DeepFriedMeme() { Auteur = "Ann", Beschrijving = "Schreeuwende eend", BasisLikes = 200, Ruisfactor = 50 });
memes.Add(new DeepFriedMeme() { Auteur = "Mo", Beschrijving = "Wazige frituur", BasisLikes = 20, Ruisfactor = 90 });krijg je:
Tim post: Kat met zonnebril - Waarde: 320 - Status: Dank
Cringe verwijderd: Lies post: Minion op maandag - Waarde: 1000 - Status: Cringe
Cringe verwijderd: Jonas post: Examenrooster als horrorfilm - Waarde: 600 - Status: Cringe
ANN POST: SCHREEUWENDE EEND - WAARDE: 700 - STATUS: DANK 🔥💀🅱️
Cringe verwijderd: MO POST: WAZIGE FRITUUR - WAARDE: 920 - STATUS: CRINGE 🔥💀🅱️
Gemiddelde waarde van de feed: 510
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.
abstractofvirtual?BerekenMemeWaardeisabstract, want er is geen standaardwaarde: elke soort moet ze zelf invullen.IsCringeisvirtual, want er is een standaard die een child mag overschrijven.base.ToString().ToUpper()hergebruikt de tekst vanMeme.DeepFriedMemebouwt niets opnieuw op.- Eén
List<Meme>volstaat voor alle soorten. Een element tijdens eenforeachuit de lijst halen gaat niet: dat crasht met “Collection was modified”.