List collectie
Een List<>
-collectie is de meest standaard collectie die je kan beschouwen als een veiligere variant op een doodnormale array. Een List
heeft alle eigenschappen die we al kennen van arrays, maar ze zijn wel krachtiger. Het giet een klasse "rond" het concept van de array, waardoor je toegang krijgt tot een hoop nuttige methoden die het werken met arrays vereenvoudigen.
List aanmaken
De klasse List<>
is een generieke klasse. Tussen de < >
tekens plaatsen we het datatype dat de lijst zal moeten gaan bevatten. Bijvoorbeeld:
List<int> alleGetallen = new List<int>();
List<bool> binaryList = new List<bool>();
List<Pokemon> pokeDex = new List<Pokemon>();
List<string[]> listOfStringarrays = new List<string[]>();
Zoals je ziet hoeven we bij het aanmaken van een List
geen begingrootte mee te geven, wat we wel bij arrays moeten doen. Dit is één van de voordelen van List
: ze groeien mee.
In dit boek behandel ik het concept generieke klassen enkel in de appendix.
Generieke klassen oftewel generic classes zijn een handig concept om je klassen nog multifunctioneler te maken doordat we zullen toelaten dat bepaalde datatypes niet hardcoded in onze klasse moet gezet worden. List<>
is zo'n eerste voorbeeld, maar er zijn er tal van anderen én je kan ook zelf dergelijke klassen schrijven. Bekijk zeker de appendix indien je dit interesseert.
De generieke List<>
klasse bevindt zich in de System.Collections.Generic
namespace. Je dient deze namespace dus als using
bovenaan toe te voegen wil je deze klasse kunnen gebruiken in C# 9.0 en ouder.
Elementen toevoegen
Via de Add()
-methode kan je elementen toevoegen aan de lijst. Je dient als parameter aan de methode mee te geven wat je aan de lijst wenst toe te voegen. Deze parameter moet uiteraard van het type zijn dat de List
verwacht.
In volgende voorbeeld maken we een List aan die objecten van het type string mag bevatten en vervolgens plaatsen we er twee elementen in.
List<string> mijnPersonages = new List<string>();
mijnPersonages.Add("Reinhardt");
mijnPersonages.Add("Mercy");
Ook meer complexe datatypes kan je dus toevoegen:
List<Pokemon> pokedex = new List<Pokemon>();
pokedex.Add(new Pokemon());
Via object syntax initializer kan dit zelfs nog sneller:
List<Pokemon> pokedex = new List<Pokemon>()
{
new Pokemon(),
new Pokemon()
};
Je kan ook een stap verder gaan en ook binnenin deze initializer syntax dezelfde soort initialize syntax gebruiken om de objecten individueel aan te maken:
List<Pokemon> pokedex = new List<Pokemon>()
{
new Pokemon() {Naam = "Pikachu", HP_Base = 5},
new Pokemon() {Naam = "Bulbasaur", HP_Base = 15}
};
Elementen indexeren
Het leuke van een List
is dat je deze ook kan gebruiken als een gewone array, waarbij je met behulp van de indexer elementen individueel kan aanroepen. Stel bijvoorbeeld dat we een lijst hebben met minstens 4 strings in. Volgende code toont hoe we de string op positie 3 kunnen uitlezen en hoe we die op positie 2 overschrijven, net zoals we reeds kenden van arrays:
Console.WriteLine(mijnPersonages[3]);
mijnPersonages[2] = "Torbjorn";
Ook de klassieke werking met loops blijft gelden. De enige aanpassing is dat List<>
niet met Length
werkt maar met Count
:
for(int i = 0 ; i < mijnPersonages.Count; i++)
{
Console.WriteLine(mijnPersonages[i])
}
Wat kan een List nog?
Interessante methoden en properties voorts zijn:
Clear()
: methode die de volledige lijst leegmaakt en de lengte (Count
) terug op 0 zet.Insert()
: methode om een element op een specifieke plaats in de lijst in te voegen.IndexOf()
: geeft de index terug van het element item in de rij. Indien deze niet in de lijst aanwezig is dan wordt -1 teruggegeven.RemoveAt()
: verwijdert een element op de index die je als parameter meegeeft.Sort()
: alle elementen in de lijst worden gesorteerd. Merk op dat dit niet altijd werkt zoals je verwacht. Lees zeker in hoofdstuk 17 de sectie omtrent "Interfaces in de praktijk" eerst voor je probeert een lijst van eigen objecten te sorteren.
Let op met het gebruik van IndexOf
en objecten. Deze methode zal controleren of de referentie dezelfde is van een bepaald object en daar de index van teruggeven. Je kan deze methode dus wel degelijk met arrays van objecten gebruiken, maar je zal enkel je gewenste object terugvinden indien je reeds een referentie naar het object hebt en dit meegeeft als parameter.
Een wereld met OOP: Pong list
Ikzelf ben fan van List. Het maakt je code vaak leesbaarder dan arrays. Voorts geeft het je de optie om dynamisch groeiende (en krimpende) arrays te hebben, zonder dat je daar veel boilerplate code voor moet schrijven. Herinner je onze Pong-code waarin we 100 balletjes op het scherm lieten vliegen?
const int AANTAL_BALLETJES = 100;
Random r = new Random();
Balletje[] veelBalletjes = new Balletje[AANTAL_BALLETJES];
for (int i = 0; i < veelBalletjes.Length; i++) //balletjes aanmaken
{
veelBalletjes[i] = new Balletje();
veelBalletjes[i].X = r.Next(10, 20);
veelBalletjes[i].Y = r.Next(10, 20);
veelBalletjes[i].VX = r.Next(-2, 3);
veelBalletjes[i].VY = r.Next(-2, 3);
}
while (true)
{
for (int i = 0; i < veelBalletjes.Length; i++)
{
veelBalletjes[i].Update(); //update alle balletjes
}
for (int i = 0; i < veelBalletjes.Length; i++)
{
veelBalletjes[i].TekenOpScherm(); //teken alle balletjes
}
System.Threading.Thread.Sleep(50);
Console.Clear();
}
Vooral de code in de while
wordt nu leesbaarder dankzij List<Balletje>
(we gaan ook ineens gebruik maken van onze nieuwe default constructor die de random startwaarde instelde):
const int AANTAL_BALLETJES = 100;
List<Balletje> veelBalletjes = List<Balletje>();
for (int i = 0; i < AANTAL_BALLETJES; i++) //balletjes aanmaken
{
veelBalletjes.Add(new Balletje());
}
while (true)
{
foreach(var bal in veelBalletjes)
{
bal.Update(); //update alle balletjes
}
foreach(var bal in veelBalletjes)
{
bal.TekenOpScherm(); //teken alle balletjes
}
System.Threading.Thread.Sleep(50);
Console.Clear();
}
Deze code zou je aan iemand die geen C# kan kunnen tonen en met een beetje geluk zal die de code begrijpen. Dat is het fijne van hogere programmeertalen zoals C#: ze zijn veel leesbaarder dan talen die dichter tegen het metaal zitten, zoals C en C++.
Als leuke extra bij C# is dat het een erg levende taal is. Jaarlijks komen er nog nieuwe concepten bij. Meestal zijn die ietwat obscuur, maar vaak maken ze de code wel een pak leesbaarder dan ervoor. Alhoewel ik graag werk met arrays, zorgen Lists er bijvoorbeeld voor dat we veel minder met vierkante haakjes moeten werken én verstoppen ze een hoop code om bijvoorbeeld lijsten te doen groeien en krimpen.
Dit verstoppen kan uiteraard soms een probleem zijn indien je hoog-performante code moet schrijven. Aan de andere kant: denk je dat jij betere code kunt schrijven dan de ontwikkelaars van de Add
-methode bij List
?