OOD Handboek

2C# basis

#Programma-opbouw

// Voertuig.cs: één klasse per bestand
namespace DeelMobiel;          // file-scoped namespace

public class Voertuig { ... }
Uitleg

Elke klasse krijgt een eigen bestand met dezelfde naam. Met een file-scoped namespace (puntkomma in plaats van accolades) scheelt het je een inspringniveau in het hele bestand.

// Program.cs: top-level statements (geen Main nodig)
using DeelMobiel;

var bedrijf = Verhuurbedrijf.Instance;
Console.WriteLine("Hallo");
Uitleg

Sinds .NET 6 mag Program.cs direct met code beginnen; de compiler maakt de Main-methode achter de schermen. Met using DeelMobiel; haal je de klassen uit jouw namespace binnen.

Functies en keywords
var
De compiler leidt het type zelf af uit de rechterkant.
// Of de klassieke vorm:
internal class Program
{
    static void Main(string[] args) { ... }
}
Uitleg

De klassieke schrijfwijze met een expliciete Main. Werkt precies hetzelfde als top-level statements; kies één van de twee per project.

Functies en keywords
static
Hoort bij de klasse zelf, niet bij één object; gedeeld door alle objecten.

#Datatypes

TypeVoorbeeldGebruik
intint minuten = 30;hele getallen
doubledouble t = 21.5;metingen, wiskunde
decimaldecimal p = 0.10m;geld (let op de m!)
boolbool ok = true;ja/nee
stringstring s = "F1";tekst
charchar c = 'A';één teken
varvar l = new List<int>();type afgeleid
GuidGuid.NewGuid()unieke id
DateTimeDateTime.Nowtijdstip

decimal en double mag je niet zomaar mengen: 0.10 is een double, 0.10m een decimal. Fout CS0664 = vergeten m.

#Control flow

if (score >= 60) Console.WriteLine("Geslaagd");
else if (score >= 50) Console.WriteLine("Herkansing");
else Console.WriteLine("Gezakt");

for (int i = 0; i < 5; i++) { ... }
foreach (Voertuig v in voertuigen) { ... }
while (!klaar) { ... }

string tekst = beschikbaar ? "vrij" : "verhuurd"; // ternary

// switch expression
decimal tarief = type switch
{
    "fiets"   => 0.10m,
    "scooter" => 0.25m,
    _         => throw new ArgumentException("Onbekend type")
};

// pattern matching
if (value is < 0 or > 100) { ... }
if (v is IOplaadbaar o && o.AccuPercentage < 20) { ... }
Uitleg

De basisbouwstenen om de stroom van je programma te sturen. De switch expression geeft direct een waarde terug en is korter dan een klassieke switch; _ vangt alle overige gevallen. Met pattern matching (is < 0 or > 100) schrijf je bereikchecks leesbaar op één regel.

Functies en keywords
switch-expressie
Kiest een waarde op basis van patronen; _ is het standaardgeval.
throw
Gooit een exception; de methode stopt direct en de fout gaat omhoog naar de aanroeper.
ArgumentException
Voor een ongeldig argument, zoals een lege tekst of verkeerde combinatie.
=>
Korte schrijfwijze voor een methode of property die één expressie teruggeeft; in LINQ ook de pijl van een lambda.
is
Controleert het type (of een patroon) en kan het object meteen in een nieuwe variabele zetten.
foreach
Loopt één voor één door alle elementen van een collectie.

#Strings

string naam = "Bob";
Console.WriteLine($"Hallo {naam}!");          // interpolatie
Console.WriteLine($"Prijs: € {prijs:0.00}");  // 2 decimalen
Console.WriteLine($"{prijs:C}");             // valuta (cultuur)
Console.WriteLine($"{opp:F1}");               // 1 decimaal
string hoog = naam.ToUpper(); int lengte = naam.Length;
naam.Contains("o"); naam.Trim(); naam.Split(';');
string.IsNullOrWhiteSpace(id);   // leeg/spaties/null?
string.Join(", ", lijst);
Uitleg

Met $"..." zet je variabelen direct in een string. Na een dubbele punt komt een opmaak: 0.00 voor twee decimalen, C voor valuta, F1 voor één decimaal. Strings zijn onveranderlijk: ToUpper() geeft een nieuwe string terug.

Functies en keywords
string.IsNullOrWhiteSpace
true als de tekst null, leeg of alleen spaties is.
string.Join
Plakt alle elementen aan elkaar met een scheidingsteken.
$"...{x}"
String-interpolatie: zet de waarde van x direct in de tekst.

#Console I/O

Console.Write("Hoe oud ben je? ");
string? invoer = Console.ReadLine();
if (int.TryParse(invoer, out int leeftijd))
    Console.WriteLine($"Je bent {leeftijd}.");
else
    Console.WriteLine("Dat is geen getal.");
Uitleg

Console.ReadLine() geeft altijd tekst (of null). int.TryParse probeert er een getal van te maken zonder exception: lukt het, dan geeft hij true en staat het getal in de out-variabele.

Functies en keywords
out
Parameter die de methode moet vullen; zo geeft een methode een extra resultaat terug.
int.TryParse
Probeert tekst naar een getal om te zetten zonder exception; geeft true bij succes.
Console.ReadLine
Leest een regel invoer als tekst (kan null zijn).
$"...{x}"
String-interpolatie: zet de waarde van x direct in de tekst.

#Collecties

int[] nummers = { 1, 2, 3 };          // vaste grootte
int eerste = nummers[0]; int aantal = nummers.Length;

List<string> namen = new();           // dynamisch
namen.Add("Alice"); namen.Remove("Alice");
int n = namen.Count; bool b = namen.Contains("Bob"); string s = namen[0];

Dictionary<string, Voertuig> perId = new();
perId["F1"] = fiets;
if (perId.TryGetValue("F1", out var v)) { ... }
perId.ContainsKey("F1");

// naar buiten alleen-lezen aanbieden
private readonly List<Voertuig> _voertuigen = new();
public IReadOnlyList<Voertuig> Voertuigen => _voertuigen;
Uitleg

Een array heeft een vaste lengte, een List<T> groeit mee. Een Dictionary zoekt razendsnel op sleutel. Het laatste stukje is een veelgebruikt patroon: intern een gewone lijst, naar buiten alleen-lezen, zodat niemand buiten de klasse de lijst kan aanpassen.

Functies en keywords
IReadOnlyList<T>
Alleen-lezen weergave van een lijst: wel lezen en doorlopen, niet toevoegen of verwijderen.
Dictionary<K,V>
Opslag van sleutel-waardeparen; snel zoeken op sleutel.
TryGetValue
Zoekt een sleutel zonder exception; geeft true en de waarde via out als hij bestaat.
out
Parameter die de methode moet vullen; zo geeft een methode een extra resultaat terug.
private
Alleen zichtbaar binnen deze klasse.
readonly
Veld mag alleen bij de declaratie of in de constructor een waarde krijgen.
=>
Korte schrijfwijze voor een methode of property die één expressie teruggeeft; in LINQ ook de pijl van een lambda.
var
De compiler leidt het type zelf af uit de rechterkant.
new()
Target-typed new: het type wordt afgeleid uit de declaratie links.
List<T>
Lijst die automatisch groeit; toevoegen met Add, aantal met Count.

#LINQ (lijsten bevragen)

var vrij = voertuigen.Where(v => v.IsBeschikbaar).ToList();
var f1   = voertuigen.FirstOrDefault(v => v.Id == "F1"); // of null
bool er  = voertuigen.Any(v => !v.IsBeschikbaar);
int n    = voertuigen.Count(v => v.IsBeschikbaar);
decimal t= ritten.Sum(r => r.Prijs);
var ids  = voertuigen.Select(v => v.Id).ToList();
var sort = voertuigen.OrderBy(v => v.Merk).ToList();  // ...Descending
var max  = metingen.Max(m => m.Waarde);
// alleen objecten van een bepaald type (veilig downcasten):
List<IOplaadbaar> opl = voertuigen.OfType<IOplaadbaar>().ToList();
Uitleg

LINQ-methodes werken op elke collectie en lezen bijna als een zin. Ze veranderen de originele lijst niet; met ToList() maak je van het resultaat een nieuwe lijst. OfType<T>() filtert op type en cast meteen, dus veilig downcasten zonder risico.

Functies en keywords
Where
LINQ: houdt alleen de elementen over die aan de voorwaarde voldoen.
FirstOrDefault
LINQ: eerste element dat voldoet, of null als er geen is.
Any
LINQ: true als minstens één element voldoet.
Count(...)
LINQ: telt de elementen die voldoen.
Sum / Max
LINQ: totaal of hoogste waarde van een eigenschap.
Select
LINQ: zet elk element om naar iets anders, bijvoorbeeld alleen het id.
OrderBy
LINQ: sorteert op de opgegeven eigenschap (oplopend).
OfType<T>()
LINQ: houdt alleen elementen van type T over en cast ze meteen; veilig downcasten.
ToList()
Maakt van het LINQ-resultaat een nieuwe List<T>.
=>
Korte schrijfwijze voor een methode of property die één expressie teruggeeft; in LINQ ook de pijl van een lambda.
var
De compiler leidt het type zelf af uit de rechterkant.
List<T>
Lijst die automatisch groeit; toevoegen met Add, aantal met Count.

#Null-handigheid

string? x = null;                 // ? = mag null zijn
int len = x?.Length ?? 0;         // ?. en ?? (standaardwaarde)
_instance ??= new Bedrijf();      // toewijzen als null
var v = Zoek(id) ?? throw new ArgumentException("Bestaat niet");
ArgumentNullException.ThrowIfNull(voertuig);
ReferenceEquals(a, b);            // zelfde object in geheugen?
Uitleg

Een vraagteken achter een type betekent: deze variabele mag null zijn. ?. roept alleen iets aan als het object niet null is, ?? geeft een reservewaarde, en ??= vult de variabele alleen als hij nog leeg is.

Functies en keywords
?.
Roept alleen aan als het object niet null is; anders is het resultaat null.
??
Geeft de rechterkant als de linkerkant null is.
??=
Vult de variabele alleen als hij nog null is.
throw
Gooit een exception; de methode stopt direct en de fout gaat omhoog naar de aanroeper.
ArgumentException
Voor een ongeldig argument, zoals een lege tekst of verkeerde combinatie.
ThrowIfNull
Gooit meteen een ArgumentNullException als het argument null is.
ReferenceEquals
true als twee variabelen naar precies hetzelfde object wijzen.
var
De compiler leidt het type zelf af uit de rechterkant.