Je hebt nu geleerd hoe je met structs orde schept in de chaos van losse variabelen. Je bent van “losse rommel” naar “nette dozen” gegaan. Maar… heb je gemerkt dat die dozen nogal passief zijn? Ze doen niks, tenzij jij er een aparte methode op loslaat.
We gaan nu effectief de leerstof van hoofdstuk 9 toepassen: de volgende stap is Object Oriented Programming (OOP).
In het intermezzo van vorige week had je een StudentData struct. Die bevatte wel de cijfers, maar kon zelf zijn gemiddelde niet berekenen. Je moest die struct telkens doorgeven aan een externe “manager” (jouw methodes).
// De struct is passief (data)
StudentData alex = ...;
// De actie moet buitenaf gebeuren
double avg = CalculateAverage(alex); Dit voelt alsof je een auto hebt, maar je moet hem zelf duwen.
De Oplossing: Slimme Objecten (Classes)
In OOP gaan we onze dozen (structs) upgraden naar Classes. Een Class is niet zomaar een container voor data. Het is een volwaardig object dat weet wat het moet doen.
We verplaatsen de logica (de methodes) IN de doos.
- Vroeger (Struct): Een lijstje met ingrediënten (Data).
- Nu (Class): Een Chef-kok die de ingrediënten heeft én weet hoe hij ze moet koken (Data + Gedrag).
// Het object is slim (data + gedrag)
Student alex = new Student("Alex", 12, 14);
// Het object doet het werk zelf!
double avg = alex.CalculateAverage();Zie je het verschil? We hoeven alex niet meer door te geven. Alex weet zelf zijn cijfers en berekent zelf zijn gemiddelde.
In dit en volgend hoofdstuk staan bij sommige oefeningen bovenaan een link naar een alternatieve manier van de oefening te maken waarbij je ook feedback krijgt. Bekijk zeker eerst dit filmpje. Indien je geen knop “open in visual studio” hebt in github dan kan je dit oplossen als volgt: open Visual studio en kies voor clone a repository:

Vervolgens copy paste je de githu-burl als daar om gevraagd wordt (voor de eerste oefening is dat https://github.com/timdams/ZIESCHERPER_TESTS_H1_RapportModule).

RapportModule (Essential)
Opgelet: de unittests projecten werden nog geschreven in .NET 7. Je zal een error krijgen dat je .NET 7 SDK moet installeren. Je kan dit oplossen door te rechterklikken op beide projecten in je solution en te kiezen voor “edit project file”. Daar verander je de TargetFramework van net7.0 naar net10.0 als je met VS 2026 werkt, of naar net9.0 als je met VS 2022 werkt. Bewaar en probeer opnieuw te runnen.
Dit geldt voor alle volgende oefeningen waarbij je een link krijgt naar een solution met unittests.
Doel: Ontwerp een klasse die een graad berekent op basis van een behaald percentage.
Specificaties:
- Klassenaam:
Rapport - Properties:
Percentage(type:int): Het behaalde punt.
- Methoden:
PrintGraad()(type:void): Toont de graad in de console.
Werking (Business Rules): De methode PrintGraad controleert de waarde van Percentage en toont de bijbehorende tekst:
| Frequentie | Output Tekst |
|---|---|
| Minder dan 50 | “Niet geslaagd” |
| 50 t.e.m. 68 | “Voldoende” |
| 69 t.e.m. 75 | “Onderscheiding” |
| 76 t.e.m. 85 | “Grote onderscheiding” |
| Meer dan 85 | “Grootste onderscheiding” |
Voorbeeldgebruik: Test je klasse met volgende code in Main:
Rapport mijnPunten = new Rapport();
mijnPunten.Percentage = 65;
mijnPunten.PrintGraad(); // Verwachte output: "Voldoende"
Rapport mijnVriendPunten = new Rapport();
mijnVriendPunten.Percentage = 89;
mijnVriendPunten.PrintGraad(); // Verwachte output: "Grootste onderscheiding"Controleer je oplossing ook via Test => Run All Tests.
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.
Nummers (Essential)
Doel: Maak een rekenmachine-klasse die bewerkingen uitvoert op twee getallen.
Specificaties:
- Klassenaam:
NummerBerekenaar - Properties:
Getal1(type:int): Het eerste getal.Getal2(type:int): Het tweede getal.
- Methoden:
Som(): returntypeintVerschil(): returntypeintProduct(): returntypeintQuotient(): returntypedouble
Werking:
Som,Verschil,Product: Voeren de standaard wiskundige bewerking uit (+,-,*) en geven het resultaat terug.Quotient: DeeltGetal1doorGetal2.- Let op: Delen door nul mag niet.
- Als Getal2 gelijk is aan 0: Toon foutboodschap “Kan niet delen door 0” in de console EN geef
0.0terug. - Anders: Geef het resultaat van de deling terug.
Voorbeeldgebruik:
NummerBerekenaar paar1 = new NummerBerekenaar();
paar1.Getal1 = 12;
paar1.Getal2 = 34;
Console.WriteLine($"Som = {paar1.Som()}"); // Output: 46
Console.WriteLine($"Verschil = {paar1.Verschil()}"); // Output: -22Deze 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.
Studentklasse (Essential)
Doel: Sla gegevens van een student op en bereken het gemiddelde.
Specificaties:
- Klassenaam:
Student - Enum:
Klassen(definieer deze buiten de klasse, mogelijke waarden:TI1,TI2,TI3) - Properties:
Naam(string)Leeftijd(int)Klas(Klassen- gebruik de enum hierboven)PuntenCommunicatie(int)PuntenProgrammingPrinciples(int)PuntenWebTech(int)
- Methoden:
BerekenGemiddelde(): Geeft het gemiddelde van de 3 puntenvakken terug alsdouble.GeefOverzicht(): Toont een rapport in de console (zie voorbeeld).
Voorbeeldgebruik:
Student student1 = new Student();
student1.Klas = Klassen.TI1;
student1.Naam = "Joske Vermeulen";
student1.Leeftijd = 21;
student1.PuntenCommunicatie = 12;
student1.PuntenProgrammingPrinciples = 15;
student1.PuntenWebTech = 13;
student1.GeefOverzicht();Verwachte Output:
Joske Vermeulen, 21 jaar
Klas: TI1
Cijferrapport:
**********
Communicatie: 12
Programming Principles: 15
Web Technology: 13
Gemiddelde: 13.3333333333
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.
PizzaTime
Doel: Maak een klasse Pizza die waarden controleert voordat ze worden opgeslagen.
Specificaties:
- Klassenaam:
Pizza - Properties (Full Properties met validatie):
Toppings(string): Beschrijving van de toppings.Diameter(int): Doorsnede in cm.Price(double): Prijs in euro.
Validatie Regels (in de set van de properties): Bij het toewijzen van een nieuwe waarde (value), controleer het volgende. Indien de waarde niet geldig is, doe je niets (de oude waarde blijft behouden).
- Price en Diameter: Moeten groter zijn dan 0. (Indien
value <= 0-> negeer). - Toppings: Mag niet leeg zijn. (Gebruik
string.IsNullOrWhiteSpace(value)om te controleren. Indientrue-> negeer).
Voorbeeldgebruik: Maak in je Main enkele pizza’s aan en probeer foute waarden in te stellen om te testen of ze inderdaad geweigerd worden.
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.
Stevens pizza (Essential)
Stagiair Steven moest voor de pizzeria om de hoek een klasse Pizza maken: toppings, een diameter en een prijs, en er mocht geen onzin in een pizza terechtkomen. Hij vroeg het aan een A.I. en plakte het resultaat in zijn project. In Pizza.cs:
internal class Pizza
{
private string toppings = "tomatensaus";
private int diameter = 25;
public double prijs;
public string Toppings
{
get
{
return toppings;
}
set
{
if (!string.IsNullOrWhiteSpace(value))
{
Toppings = value;
}
}
}
public int Diameter
{
get
{
return diameter;
}
set
{
if (value > 0)
{
diameter = diameter;
}
}
}
public static void ToonInfo()
{
Console.WriteLine($"Pizza met {Toppings}, {Diameter} cm, {prijs} euro");
}
}En in Main:
Pizza margherita;
margherita.Toppings = "tomaat en mozzarella";
margherita.Diameter = 30;
Console.WriteLine("Wat kost de margherita?");
double prijs = Convert.ToDouble(Console.ReadLine());
if (prijs > 0)
{
margherita.prijs = prijs;
}
margherita.ToonInfo();Deel 1. Neem de code over: de klasse in een apart bestand, de rest in Main. Het project compileert niet. De compiler geeft vijf fouten en één waarschuwing. Laat de waarschuwing even liggen: de vijf fouten hebben samen maar twee oorzaken. Welke, en hoe los je ze 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.
Deel 2. Nu compileert het, met nog altijd die ene waarschuwing. Voer het uit. Het programma crasht nog voor het de prijs vraagt. Zoek de oorzaak en los ze op. Daarna loopt het wel, maar met 12 als prijs toont het Pizza met tomaat en mozzarella, 25 cm, 12 euro, terwijl Steven de diameter op 30 zette. Zoek ook die fout. De waarschuwing helpt je.
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. Het programma doet nu wat Steven wou, zonder fouten of waarschuwingen. Een collega gebruikt de klasse voor een tweede pizza:
Pizza hawaii = new Pizza();
hawaii.Toppings = "ham en ananas";
hawaii.prijs = -4;
hawaii.ToonInfo();Ook dat compileert, en het toont Pizza met ham en ananas, 25 cm, -4 euro. Welke twee keuzes in Stevens code maken dat mogelijk? Herschrijf de klasse en Main zodat geen enkele pizza een prijs van 0 of minder kan krijgen, ook niet in de code van de collega.
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 de zes fouten gaven er twee een compileerfout en één een waarschuwing. De stack overflow, de publieke instantievariabele en de controle in
Mainvond de compiler niet. - Lees ook de waarschuwingen.
CS1717wees de lijn met de fout inDiameteraan, terwijl het programma gewoon startte. - Tussen
Toppings = value;entoppings = value;zit één hoofdletter: het eerste schrijft naar de property, het tweede naar de instantievariabele. - Zie De new operator, Object methoden (over
static), Full property: set gedeelte en Full property met toegangscontrole.
Figuren
Doel: Werken met overerving of losse klassen (hier losse klassen) en validatie.
Specificaties:
| Klasse | Property | Type | Validatie in set |
|---|---|---|---|
| Rechthoek | Lengte |
int |
Indien value < 1, verander niets. Anders value. |
Breedte |
int |
Indien value < 1, verander niets. Anders value. |
|
Methode: ToonOppervlakte() |
void |
Berekent Lengte * Breedte en toont resultaat. | |
| Driehoek | Basis |
int |
Indien value < 1, verander niets. Anders value. |
Hoogte |
int |
Indien value < 1, verander niets. Anders value. |
|
Methode: ToonOppervlakte() |
void |
Berekent (Basis * Hoogte) / 2 en toont resultaat. |
Let op: Rechthoek en Driehoek zijn hier twee aparte klassen en hebben niets met elkaar te maken, behalve dat ze toevallig gelijkaardige methoden hebben.
Opdracht: Maak van elke figuur een instantie in je Main en roep ToonOppervlakte aan.
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.
MiniRPG (Final Essentials)
Een Final Essentials oefening is een opgave waarin alle leerstof van de voorbije oefeningen aan bod komt.
Doel: Bouw een mini-RPG systeem waarin je een held aanmaakt, traint en laat vechten.
Deel 1: De Setup
Maak eerst de nodige basisstructuur aan.
- Enum
HeldType: Definieer deze buiten je klasse.- Opties:
Krijger,Magiër,Boogschutter.
- Opties:
- Klasse
Held:- Properties:
Naam(string): Mag niet leeg zijn. Indien leeg, stel in op “Naamloze Held”.Type(HeldType): Het type van de held.Level(int): Private set. Begint altijd op 1.XP(int): Experience Points. Private set. Begint op 0.Levenspunten(int): Huidige HP. Mag niet onder 0 gaan.MaxLevenspunten(int): Read-only property die volgende formule gebruikt:100 + (Level * 10). (Bij level 1 is dit dus 110).
- Properties:
Deel 2: De Actie
Voeg nu gedrag toe aan je held.
- Methoden:
VerkrijgErvaring(int punten)(void):- Tel
puntenop bijXP. - Level Up Logica: Elke 100 XP stijgt de held een level.
- Zolang
XP >= 100:- Verminder XP met 100.
- Verhoog
Levelmet 1. - Verhoog
Levenspuntenmet 10 (omdat MaxHP ook stijgt). - Toon: “Level Up! [Naam] is nu level [Level]!”
- Tel
ValAan()(int):- Genereert schade gebaseerd op het
Levelen een basiswaarde. - Formule:
10 + Level. (Simpel gehouden voor nu). - Return dit getal.
- Genereert schade gebaseerd op het
IncasseerSchade(int schade)(void):- Trek
schadeaf vanLevenspunten. - Zorg dat
Levenspuntenniet onder 0 zakt (controleer dit in de property setter of hier). - Als
Levenspunten0 bereikt: Toon “[Naam] is verslagen…”.
- Trek
ToonStats()(string):- Geeft een samenvatting terug, bv:
- “[Naam] (Level [Level] [Type]) - HP: [Levenspunten]/[MaxLevenspunten] - XP: [XP]”
Voorbeeldgebruik in Main:
Held conan = new Held();
conan.Naam = "Conan";
conan.Type = HeldType.Krijger;
conan.Levenspunten = conan.MaxLevenspunten;
Console.WriteLine(conan.ToonStats());
// Output: Conan (Level 1 Krijger) - HP: 110/110 - XP: 0
// Conan traint
conan.VerkrijgErvaring(150);
// Output: Level Up! Conan is nu level 2!
Console.WriteLine(conan.ToonStats());
// Output: Conan (Level 2 Krijger) - HP: 120/120 - XP: 50
// Conan vecht
int schade = conan.ValAan();
Console.WriteLine($"Conan doet {schade} schade.");
// Conan wordt geraakt
conan.IncasseerSchade(50);
Console.WriteLine(conan.ToonStats());
// Output: Conan (Level 2 Krijger) - HP: 70/120 - XP: 50Extra Uitdaging (Optioneel): Maak de ValAan methode slimmer gebaseerd op HeldType.
Krijger: Doet10 + (Level * 2)schade (fysiek sterk).Magiër: Doet5 + (Level * 3)schade (begint zwak, wordt heel sterk).Boogschutter: Doet8 + (Level * 2)schade.
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.