- Een interface is enkel een belofte: methoden en properties zonder
publicen zonder body, geen instantievariabelen en geen constructor. Haar naam begint met eenI(uitleg). - De klasse die een interface aanhangt, schrijft alles ervan uit, en wel
public. Achter het dubbele punt komt eerst de parentklasse, dan de interfaces:class Batman : Man, ISuperHeld(uitleg). - Een variabele, parameter of lijst mag een interface als type hebben, zoals
List<IMinister>. Of een object een interface heeft, vraag je metis:if (mens is IVloeker vloeker) vloeker.Vloek();(uitleg). IComparablebestaat al in .NET: schrijf ze niet opnieuw, maar implementeerCompareTo. Geeft die een negatief getal, nul of een positief getal terug, dan werktSort()ook voor je eigen klasse (uitleg).
Stevens superhelden (Essential)
Stagiair Steven moest de eerste twee helden van een vechtspel maken. Batman en Zorro zijn allebei een Man, en ze beloven allebei wat een ISuperHeld belooft. Een A.I. schreef de code. Steven zette elk stuk in een eigen bestand en leverde het in zonder één keer te compileren:
//ISuperHeld.cs
interface ISuperHeld
{
int power;
public void SchietLasers();
int Power { get; set; }
}//Man.cs
internal class Man
{
public void Wandel()
{
Console.WriteLine("Ik wandel rustig verder.");
}
}//Batman.cs
internal class Batman : ISuperHeld, Man
{
public int Power { get; set; } = 80;
public void SchietLasers()
{
Console.WriteLine("Batman heeft geen lasers en gooit een batarang.");
}
}//Zorro.cs
internal class Zorro : Man, ISuperHeld
{
int Power { get; set; } = 60;
public void SchietLasers()
{
Console.WriteLine("Zorro kerft een Z in de muur.");
}
}//Program.cs
static void Main(string[] args)
{
List<ISuperHeld> helden = new List<ISuperHeld>();
helden.Add(new Batman());
helden.Add(new Zorro());
helden.Add(new ISuperHeld());
foreach (ISuperHeld held in helden)
{
held.SchietLasers();
Console.WriteLine($"Power: {held.Power}");
if (held is Man man)
{
man.Wandel();
}
}
}Deel 1. Maak een nieuw project met een apart bestand voor de interface en voor elke klasse, en plak Stevens code erin. Er zitten vier fouten in die de compiler vindt. Lees de meldingen in de Error List en herstel ze. Let op: ze verschijnen niet allemaal tegelijk.
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. Alles compileert. Steven heeft nog drie vragen. Beantwoord ze eerst op papier, en test daarna.
Een collega zegt dat
public void SchietLasers();in de interface ook fout is: “in een interface schrijf je geen access modifiers”. Heeft hij gelijk?Steven wil dat elke superheld met 100 power start. Zijn A.I. zet daarom een constructor in de interface:
interface ISuperHeld { public void SchietLasers(); int Power { get; set; } ISuperHeld() { Power = 100; } }Wat zegt de compiler, en waar hoort die beginwaarde dan wel?
Steven wil van de interface een abstracte klasse
SuperHeldmaken, metinternal class Batman : Man, SuperHeld. Waarom lukt dat niet?
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.
- In een interface staan enkel de signaturen van methoden en properties: geen instantievariabelen, geen constructors en geen code. Zie Interface regels, met daaronder de tabel “Interface of abstracte klasse?”.
- De interface schrijft geen
public, maar de klasse die ze implementeert moet het wel doen. Anders telt het lid niet mee. - Eerst de parentklasse, dan de interfaces. Zie Meerdere interfaces.
- Van een interface maak je geen object. Een variabele of een
List<ISuperHeld>mag wel van dat type zijn, en daarin stop je objecten van klassen die de interface implementeren. - De compiler kijkt eerst of de interface en de klassen kloppen, en pas daarna naar de code in je methoden. Zolang er een fout in een klasse of interface staat, zie je de fout in
Maindus niet. Visual Studio kijkt je code ook al na terwijl je typt, en kan de fout inMaindaardoor soms wel al tonen.
CO2-teller van de campus (Essential)
De hogeschool wil weten hoeveel CO2 de campus uitstoot, en jij maakt de teller. Op de campus staan aula’s, computerlabo’s, pendelbussen en kamerplanten. Die vier hebben niets met elkaar gemeen: geen enkele erft van een andere. Op één ding na: drie van de vier stoten CO2 uit.
Maak een interface ICo2Uitstoot met twee methoden, allebei zonder parameters:
BerekenUitstootgeeft de uitstoot terug, alsint.VerlaagUitstootgeeft niets terug en maakt de uitstoot van dat object kleiner.
Maak vier klassen, elk in een eigen bestand:
| Klasse | Property | Uitstoot | Verlagen |
|---|---|---|---|
Aula |
Volume (int, in kubieke meter) |
het volume maal een factor die start op 10 | de factor zakt met 1, maar niet onder 1 |
Computerlabo |
AantalPcs (int) |
het aantal pc’s maal een factor die start op 100 | de factor zakt met 10, maar niet onder 10 |
Pendelbus |
Motor, van een eigen enum MotorType met Diesel, Hybride en Elektrisch |
diesel 150, hybride 90, elektrisch 20 | een dieselbus wordt hybride, een hybride bus elektrisch; elektrisch blijft elektrisch |
Kamerplant |
geen | krijgt de interface niet |
De factor is een private instantievariabele: wie de klasse gebruikt, ziet ze niet. De uitstoot zelf bewaar je nergens, je berekent ze telkens opnieuw.
Zet in Main deze acht objecten in één lijst, in deze volgorde. Ze hebben enkel object gemeen, dus het wordt een List<object>:
List<object> campus = new List<object>();
campus.Add(new Kamerplant());
campus.Add(new Aula() { Volume = 300 });
campus.Add(new Computerlabo() { AantalPcs = 20 });
campus.Add(new Pendelbus() { Motor = MotorType.Diesel });
campus.Add(new Kamerplant());
campus.Add(new Aula() { Volume = 120 });
campus.Add(new Computerlabo() { AantalPcs = 35 });
campus.Add(new Pendelbus() { Motor = MotorType.Elektrisch });Schrijf daarna een programma dat:
- van elk object de naam van zijn klasse en zijn uitstoot toont. De kamerplanten sla je over;
- de gemiddelde uitstoot van alle acht objecten berekent. De kamerplanten tellen mee, met een uitstoot van 0;
- toont welk object het meest uitstoot, met zijn index in de lijst;
- de uitstoot van elk object verlaagt en alles opnieuw toont.
Voorbeelduitvoer:
Aula: 3000
Computerlabo: 2000
Pendelbus: 150
Aula: 1200
Computerlabo: 3500
Pendelbus: 20
Gemiddelde uitstoot: 1233,75
Hoogste uitstoot: Computerlabo op index 6 (3500)
Na het verlagen:
Aula: 2700
Computerlabo: 1800
Pendelbus: 90
Aula: 1080
Computerlabo: 3150
Pendelbus: 20
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 aula, een pendelbus en een kamerplant hebben geen gemeenschappelijke parent: een kamerplant “is” geen aula. Een interface heeft dat ook niet nodig. Ze belooft enkel dat een klasse bepaalde methoden heeft. Zie Interfaces in OOP.
- In een
List<object>kan je per element enkel watobjectkan. Metasofisvraag je of het de interface heeft, en pas dan roep jeBerekenUitstootop. Zie Alles samen: polymorfisme, interfaces en is/as. GetType().Namegeeft de naam van de klasse.GetType()alleen zet er ook de naamruimte van je project voor, zoalsCo2Teller.Aula.
Kotfeest: wie draait de muziek? (Essential)
Vrijdagavond, kotfeest. Iedereen brengt iets mee: Jana haar smartphone, Bram zijn fototoestel en zijn oude wekkerradio, Sofie haar bluetoothbox. Je project heet Kotfeest, en elke interface en klasse staat in een eigen bestand:
interface ICamera
{
void MaakFoto();
}interface IMuziek
{
void SpeelAf(string nummer);
}internal class Toestel
{
public string Eigenaar { get; set; }
}internal class Smartphone : Toestel, ICamera, IMuziek
{
public void MaakFoto()
{
Console.WriteLine($"Klik! (gsm van {Eigenaar})");
}
public void SpeelAf(string nummer)
{
Console.WriteLine($"Gsm van {Eigenaar} speelt {nummer}, blikkerig.");
}
}internal class Fototoestel : Toestel, ICamera
{
public void MaakFoto()
{
Console.WriteLine($"Klik! Flits! (fototoestel van {Eigenaar})");
}
}internal class Bluetoothbox : Toestel, IMuziek
{
public void SpeelAf(string nummer)
{
Console.WriteLine($"BOEM BOEM: {nummer}");
}
}internal class Wekkerradio : Toestel
{
public void SpeelAf(string nummer)
{
Console.WriteLine($"De wekkerradio kraakt {nummer}.");
}
}En in Program.cs:
static void Main(string[] args)
{
List<Toestel> opKot = new List<Toestel>();
opKot.Add(new Smartphone() { Eigenaar = "Jana" });
opKot.Add(new Fototoestel() { Eigenaar = "Bram" });
opKot.Add(new Bluetoothbox() { Eigenaar = "Sofie" });
opKot.Add(new Wekkerradio() { Eigenaar = "Bram" });
foreach (Toestel toestel in opKot)
{
Console.Write($"{toestel.GetType().Name} van {toestel.Eigenaar}: ");
if (toestel is ICamera)
{
Console.Write("camera ");
}
if (toestel is IMuziek)
{
Console.Write("muziek");
}
Console.WriteLine();
}
List<IMuziek> boxen = new List<IMuziek>();
List<ICamera> cameras = new List<ICamera>();
foreach (Toestel toestel in opKot)
{
if (toestel is IMuziek muziek)
{
boxen.Add(muziek);
}
if (toestel is ICamera camera)
{
cameras.Add(camera);
}
}
StartPlaylist(boxen, "Dancing Queen");
MaakGroepsfoto(cameras);
Console.WriteLine(boxen[0] == cameras[0]);
}
static void StartPlaylist(List<IMuziek> boxen, string nummer)
{
foreach (IMuziek box in boxen)
{
box.SpeelAf(nummer);
}
}
static void MaakGroepsfoto(List<ICamera> cameras)
{
foreach (ICamera camera in cameras)
{
camera.MaakFoto();
}
}Deel 1. Schrijf op papier wat dit programma toont, lijn per lijn. Typ de code pas daarna over en vergelijk. Beantwoord daarna nog twee vragen:
- De wekkerradio heeft toch een methode
SpeelAf? Waarom speelt hij niet mee op het feestje? - Wat moet je in de code van
Wekkerradiotoevoegen zodat hij wel meespeelt? Het is minder dan één regel.
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. Typ deze regels onderaan in je Main. Zeg eerst voor elke genummerde regel of ze compileert. Zo ja, wat toont ze? Zo nee, waarom niet? Test daarna. Een regel die niet compileert, zet je in commentaar voor je de volgende test.
IMuziek muziek = new Smartphone() { Eigenaar = "Jana" };
muziek.SpeelAf("Mr. Brightside"); // 1
muziek.MaakFoto(); // 2
ICamera camera = muziek; // 3
if (muziek is ICamera foto) // 4
{
foto.MaakFoto();
}Tot slot: waarom is ICamera een interface, en geen klasse Camera met een methode MaakFoto?
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. Sofie brengt ook haar draaitafel mee. Een draaitafel kan alles wat een IMuziek kan, en daarnaast scratchen.
- Maak een interface
IDJdie erft vanIMuzieken er één methode bij zet:void Scratch();. Hoe een interface van een andere erft, zie je bijIGodin Meerdere interfaces. - Maak een klasse
Draaitafeldie erft vanToestelenIDJaanhangt.SpeelAftoont bijvoorbeeldDe draaitafel van Sofie legt Dancing Queen op.,ScratchtoontWikka wikka!. - Voeg in
Mainna de wekkerradio een draaitafel van Sofie toe aanopKot. Laat op het einde vanMainelk toestel uitopKotdat eenIDJis, scratchen.
Voorspel eerst: komt de draaitafel in de playlist, ook al staat er nergens IMuziek achter de klasse? Haal de regels van deel 2 weg en voer uit. De wekkerradio uit deel 1 speelt intussen mee.
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 erft van hoogstens één klasse, maar mag zoveel interfaces aanhangen als ze wil. De smartphone zit daardoor in een lijst van camera’s en in een lijst van muziektoestellen tegelijk. Zie Meerdere interfaces.
- Een interface mag het type van een lijst of een parameter zijn, zoals
List<ICamera>.MaakGroepsfotohoeft niet te weten welke toestellen erin zitten. Zie Interfaces in de praktijk. iskijkt naar de interfaces die een klasse aanhangt, niet naar de namen van haar methoden.- Via een variabele van een interface kan je enkel wat die interface belooft.
- Een interface die van een andere erft, neemt al haar beloftes over.
Pokémon interfaces (Essential)
Shadow Pokémon (meer uitleg) zijn Pokémon met een duister hart. Je kan ze zuiveren (purify), en elke soort heeft daar een eigen manier voor. Je bouwt verder op je Pokemon-klasse uit Pokémon deel 2, met de constructor met zes base-stats.
- Maak een interface
IShadowmet een methodePurify(zonder parameters, zonder returnwaarde) en een read-only propertyIsGezuiverdvan het typebool. - Maak twee klassen die erven van
PokemonenIShadowaanhangen. Elke klasse heeft een default constructor die de base-stats viabase(...)doorgeeft en deNaaminvult:ShadowLugia: naamLugia, base-stats 106, 90, 130, 90, 154 en 110. Lugia is pas gezuiverd na drie keerPurify.ShadowMewtwo: naamMewtwo, base-stats 106, 110, 90, 154, 90 en 130. Mewtwo is gezuiverd na één keerPurify.
- Schrijf in
Programtwee static methoden die eenList<Pokemon>krijgen:ToonShadowstoont van elke Shadow Pokémon die nog niet gezuiverd isShadow:met de naam erachter. Is er geen enkele, dan toont zeGeen shadows meer.ZuiverAllesroept van elke Shadow Pokémon in de lijstPurifyop.
Testcode. Zet deze code in je Main. Je klassen werken als je exact deze uitvoer krijgt.
List<Pokemon> team = new List<Pokemon>();
team.Add(new Pokemon(35, 55, 40, 50, 50, 90) { Naam = "Pikachu" });
team.Add(new ShadowLugia());
team.Add(new Pokemon(45, 49, 49, 65, 65, 45) { Naam = "Bulbasaur" });
team.Add(new ShadowMewtwo());
Console.WriteLine("Voor het zuiveren:");
ToonShadows(team);
ZuiverAlles(team);
Console.WriteLine("Na 1 keer zuiveren:");
ToonShadows(team);
ZuiverAlles(team);
ZuiverAlles(team);
Console.WriteLine("Na 3 keer zuiveren:");
ToonShadows(team);
Console.WriteLine(team[1] is IShadow);Voor het zuiveren:
Shadow: Lugia
Shadow: Mewtwo
Na 1 keer zuiveren:
Shadow: Lugia
Na 3 keer zuiveren:
Geen shadows meer.
True
Waarom heeft IShadow die property IsGezuiverd nodig? Kijk naar de laatste regel van de uitvoer. En waarom kan IShadow geen abstracte klasse Shadow zijn?
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 interface mag ook properties beloven, zonder body:
bool IsGezuiverd { get; }. - Elke klasse vult de belofte op haar eigen manier in. Wie
Purifyoproept, hoeft niet te weten welke Shadow Pokémon hij voor zich heeft. - Eerst de parentklasse, dan de interface:
ShadowLugia : Pokemon, IShadow. Zie Meerdere interfaces. - Pattern matching werkt ook met een interface:
if (pokemon is IShadow shadow). Zie Alles samen: polymorfisme, interfaces en is/as.
Figuren sorteren (Essential)
Je bouwt verder op Geometrische figuren uit hoofdstuk 14: de abstracte klasse GeometrischeFiguur met Rechthoek, Vierkant en Driehoek. Maak een kopie van dat project. Je gaat een lijst figuren sorteren op oppervlakte, met de Sort-methode van List.
Stap 0: het probleem. Zet figuren.Sort(); in de testcode van hoofdstuk 14, net voor de foreach, en voer uit. Lees de foutmelding. Zet daarna : IComparable achter internal abstract class GeometrischeFiguur en compileer. 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.
Deel 1. Schrijf CompareTo in GeometrischeFiguur, zodat Sort de figuren van klein naar groot zet volgens hun oppervlakte. Is obj geen GeometrischeFiguur, dan gooi je een ArgumentException.
Onder CompareTo zet Visual Studio een groene lijn (CS8767). Die heeft met nullable types te maken, zoals CS8618 in hoofdstuk 9: je mag ze laten staan.
Testcode deel 1.
List<GeometrischeFiguur> figuren = new List<GeometrischeFiguur>();
figuren.Add(new Rechthoek(3, 4));
figuren.Add(new Vierkant(4));
figuren.Add(new Driehoek(3, 5));
figuren.Add(new Rechthoek(1, 2));
figuren.Add(new Driehoek(4, 4));
figuren.Sort();
foreach (GeometrischeFiguur figuur in figuren)
{
Console.WriteLine(figuur);
}Rechthoek van 2 op 1: 4 hoeken, oppervlakte 2
Driehoek van 5 op 3: 3 hoeken, oppervlakte 7,5
Driehoek van 4 op 4: 3 hoeken, oppervlakte 8
Rechthoek van 4 op 3: 4 hoeken, oppervlakte 12
Vierkant van 4 op 4: 4 hoeken, oppervlakte 16
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. Voeg in de testcode een Driehoek(4, 6) toe, na de andere figuren. Die heeft dezelfde oppervlakte als de Rechthoek(3, 4). Pas CompareTo aan: bij een gelijke oppervlakte komt de figuur met de minste hoeken eerst.
Rechthoek van 2 op 1: 4 hoeken, oppervlakte 2
Driehoek van 5 op 3: 3 hoeken, oppervlakte 7,5
Driehoek van 4 op 4: 3 hoeken, oppervlakte 8
Driehoek van 6 op 4: 3 hoeken, oppervlakte 12
Rechthoek van 4 op 3: 4 hoeken, oppervlakte 12
Vierkant van 4 op 4: 4 hoeken, oppervlakte 16
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. Nu van groot naar klein. Draai enkel de vergelijking van de oppervlakte om; bij een gelijke oppervlakte komt de figuur met de minste hoeken nog altijd eerst. Sorteer deze keer geen lijst, maar een array: vervang in de testcode van deel 2 figuren.Sort(); en de foreach door:
GeometrischeFiguur[] reeks = figuren.ToArray();
Array.Sort(reeks);
foreach (GeometrischeFiguur figuur in reeks)
{
Console.WriteLine(figuur);
}Vierkant van 4 op 4: 4 hoeken, oppervlakte 16
Driehoek van 6 op 4: 3 hoeken, oppervlakte 12
Rechthoek van 4 op 3: 4 hoeken, oppervlakte 12
Driehoek van 4 op 4: 3 hoeken, oppervlakte 8
Driehoek van 5 op 3: 3 hoeken, oppervlakte 7,5
Rechthoek van 2 op 1: 4 hoeken, oppervlakte 2
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.
SortenArray.Sortsorteren je eigen objecten enkel als hun klasseIComparableaanhangt. Zonder die interface crashtSort. Zie Sorteren met Array.Sort en de IComparable interface.CompareTogeeft een negatief getal als het huidige object eerst moet komen, 0 als het gelijk is, en een positief getal als het naobjmoet komen. Draai je de tekens om, dan draait de volgorde om.- Ook een abstracte klasse mag een interface aanhangen. Haar children erven de
CompareTogewoon mee. IComparablebestaat al in .NET. Schrijf ze niet zelf opnieuw: jij levert enkel deCompareTo.
Hacker Simulator (Final Essentials, GPT)
Tijd om in de digitale schaduwen te duiken. Je bouwt een systeem om verschillende soorten computersystemen te infiltreren. Elk systeem heeft zijn eigen zwaktes, maar dankzij een universele interface kan je hacker-tool ze allemaal aan.

De namen in deze opgave zijn Engels. Houd dat vol in je eigen code, ook voor je private instantievariabelen: half Engels, half Nederlands kost punten.
Stap 1: de interface. Maak een interface IHackable met:
- een read-only property
SecurityLevel(int): hoe moeilijk het systeem te kraken is, van 1 tot 100; - een methode
bool TryHack(string password): probeert in te breken en geefttrueterug als dat lukt; - een methode
void ShowData(): toont de geheime data als het systeem gehackt is, en andersACCESS DENIED.
Stap 2: de doelwitten. Maak drie klassen die IHackable implementeren. Elk doelwit onthoudt met een bool of het al gehackt is. Eenmaal gehackt, blijft TryHack true teruggeven, welk wachtwoord er ook komt.
BankServer:SecurityLevel90.TryHacklukt met het wachtwoordMoney123of metBACKDOOR.ShowDatatoontTransacties: Miljoenen gestolen!.SocialMediaAccount:SecurityLevel30. Het wachtwoord krijgt het account mee via zijn constructor, want elk account heeft een ander.TryHacklukt met dat wachtwoord.ShowDatatoontDM geschiedenis: Genante selfies gevonden..SmartFridge(een IoT-toestel):SecurityLevel5.TryHacklukt altijd, wat het wachtwoord ook is.ShowDatatoontMelk is op. Temperatuur: 4 graden..
Stap 3: de brute force tool. Maak een klasse HackerTool met een methode RunBruteForce(List<IHackable> targets). Die loopt door de lijst en probeert bij elk doelwit de veelvoorkomende wachtwoorden 123456, password, admin en Money123, in die volgorde. Zodra er een lukt, stopt ze met proberen bij dat doelwit. Gebruik daarvoor een while met een bool, geen break. Dan:
- lukte het: toon
SYSTEM BREACHED:met de naam van de klasse erachter, roepShowData()op en toonSecurity Level was:met het niveau; - lukte niets: toon
Failed to crack system..
HackerTool kent enkel de interface. Ze vraagt nooit met is welk soort doelwit ze voor zich heeft.
Testcode. Zet deze code in je Main. Je klassen werken als je exact deze uitvoer krijgt.
List<IHackable> targets = new List<IHackable>();
targets.Add(new BankServer());
targets.Add(new SocialMediaAccount("123456"));
targets.Add(new SocialMediaAccount("Zomer2024!"));
targets.Add(new SmartFridge());
targets[1].ShowData();
HackerTool tool = new HackerTool();
tool.RunBruteForce(targets);
Console.WriteLine(targets[1].TryHack("wrong"));ACCESS DENIED
SYSTEM BREACHED: BankServer
Transacties: Miljoenen gestolen!
Security Level was: 90
SYSTEM BREACHED: SocialMediaAccount
DM geschiedenis: Genante selfies gevonden.
Security Level was: 30
Failed to crack system.
SYSTEM BREACHED: SmartFridge
Melk is op. Temperatuur: 4 graden.
Security Level was: 5
True
Stap 4: de vraag. Waarom is IHackable een interface, en geen abstracte klasse Hackable?
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.
HackerToolwerkt met eenList<IHackable>en weet niet welke doelwitten erin zitten. Komt er morgen een klasseSmartWatchbij dieIHackableaanhangt, dan verandert er inHackerToolniets.- Ook een property hoort in het contract:
int SecurityLevel { get; }, zonder body. - Kies een interface als klassen enkel een belofte delen, een abstracte klasse als ze ook code of instantievariabelen delen. Zie de tabel “Interface of abstracte klasse?” onder Interface regels.
PokéDex met foreach (PRO)
Deze oefening gaat verder dan de leerstof: IEnumerable zelf implementeren staat niet in het boek.
Maak een klasse PokeDex (in code zonder é) met een private List<Pokemon> en een methode VoegToe(Pokemon pokemon). Deze code moet werken met je Pokemon-klasse:
PokeDex dex = new PokeDex();
dex.VoegToe(new Pokemon(35, 55, 40, 50, 50, 90) { Naam = "Pikachu" });
dex.VoegToe(new Pokemon(45, 49, 49, 65, 65, 45) { Naam = "Bulbasaur" });
foreach (Pokemon pokemon in dex)
{
Console.WriteLine(pokemon.Naam);
}Pikachu
Bulbasaur
Zonder meer zegt de compiler CS1579: foreach statement cannot operate on variables of type 'PokeDex' because 'PokeDex' does not contain a public instance or extension definition for 'GetEnumerator'. Zoals Sort een CompareTo nodig heeft, heeft foreach een GetEnumerator nodig. Die methode belooft de interface IEnumerable (documentatie). Twee tips:
IEnumerablestaat inSystem.Collections: zetusing System.Collections;bovenaan het bestand van jePokeDex. Vergeet je dat, dan denkt de compiler dat je de versie uitSystem.Collections.Genericbedoelt, en krijg jeCS0305.- De interface heeft één methode:
IEnumerator GetEnumerator(). Je private lijst heeft die methode al.
Werkt het? Vervang dan in de foreach Pokemon pokemon door var pokemon. Wat zegt de compiler, 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.
Game (PRO)
Een groter project voor wie nog wil: een klein spel op een kaart van 20 bij 20 vakjes. Er is geen oplossing. Het klasseschema en de interfaces staan onderaan deze opgave.
Het spel.
- De speler (
X) start in kolom 0, rij 10: links, in het midden. Hij wint als hij de overkant haalt, kolom 19. - Op elk vakje staat hoogstens één element: de speler, een rots (
O), een monster (M) of een RockDestroyer (D). Een leeg vakje isnull. - Bij de start komen er rotsen en monsters op willekeurige vakjes, maar niet in kolom 0. Hoeveel, kies je zelf.
- Per beurt doet de speler één ding: één vakje bewegen (omhoog, omlaag, links of rechts) of naar rechts schieten. Bij een schot verdwijnt wat er op het vakje rechts van hem staat, een rots of een monster. Hij kan niet door rotsen of monsters wandelen, en niet van de kaart af.
- Daarna doet elk monster één ding:
- Een gewoon monster beweegt één vakje in een willekeurige richting. Is dat vakje bezet of ligt het buiten de kaart, dan blijft het staan.
- Een RockDestroyer kijkt eerst naar het vakje links van hem. Staat daar een rots of de speler, dan schiet hij, en verdwijnt wat daar stond. Anders beweegt hij zoals een gewoon monster.
- Wordt de speler neergeschoten, dan is het spel verloren.
Eén beurt.
- Vraag de speler wat hij wil doen:
U(omhoog),D(omlaag),L(links),R(rechts) ofS(schieten). - Voer dat uit.
- Staat de speler in kolom 19? Dan is hij gewonnen.
- Laat elk monster zijn ene actie doen.
- Is de speler neergeschoten? Dan is hij verloren.
- Teken de kaart opnieuw.
Werk in delen.
- Deel 1: de klassen uit het schema, een kaart
MapElement[,]van 20 bij 20 met rotsen en de speler erop, en een methode die de kaart tekent. - Deel 2: de speler beweegt en schiet.
- Deel 3: de monsters, eerst de gewone, daarna de RockDestroyers.
De meeste logica komt in je Main of in een klasse Manager. De klasse Player kan niet beslissen wat een monster doet: dan zou de speler als het ware in het hoofd van het monster zitten, en dat is tegen het idee van OOP. Voor het toeval gebruik je één private static Random.
Extra’s. Dit is een minimale beschrijving. Voeg naar believen toe:
- de speler heeft levens;
- monsters hebben levens;
- andere soorten monsters, bijvoorbeeld slimmere;
- meerdere levels, met telkens andere of meer monsters;
- meerdere spelers;
- verder schieten, of in andere richtingen.
Klasseschema.

Location is van het type Point (compositie). Point is een zelfgemaakte mini-klasse die er minimaal zo uitziet:
class Point
{
public int X{get;set;}
public int Y{get;set;}
}In je abstracte klasse MapElement komt dus iets in de trend van public Point Location {get;set;} = new Point();.
De interfaces:

Het spel in actie. Deze versie spreekt de speler bij naam aan. Dat mag, maar hoeft niet.

Vraag. Eén van de twee interfaces had ook een abstracte klasse tussen MapElement en Monster/Player kunnen zijn. Welke, en waarom kan de andere enkel een interface zijn?
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 elk element heeft, een plaats en een manier om getekend te worden, staat in de abstracte klasse
MapElement. Wat maar sommige elementen kunnen, bewegen en schieten, staat in een interface. - Een speler die beweegt én schiet, hangt twee interfaces aan:
Player : MapElement, IMoveable, IDestroyer.