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.
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.
static- Hoort bij de klasse zelf, niet bij één object; gedeeld door alle objecten.
#Datatypes
| Type | Voorbeeld | Gebruik |
|---|---|---|
int | int minuten = 30; | hele getallen |
double | double t = 21.5; | metingen, wiskunde |
decimal | decimal p = 0.10m; | geld (let op de m!) |
bool | bool ok = true; | ja/nee |
string | string s = "F1"; | tekst |
char | char c = 'A'; | één teken |
var | var l = new List<int>(); | type afgeleid |
Guid | Guid.NewGuid() | unieke id |
DateTime | DateTime.Now | tijdstip |
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.
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.
string.IsNullOrWhiteSpacetrueals 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
xdirect 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.
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
truebij succes. Console.ReadLine- Leest een regel invoer als tekst (kan null zijn).
$"...{x}"- String-interpolatie: zet de waarde van
xdirect 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.
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
trueen de waarde viaoutals 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 metCount.
#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.
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:
trueals 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
Tover 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 metCount.
#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.
?.- 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
ArgumentNullExceptionals het argument null is. ReferenceEqualstrueals twee variabelen naar precies hetzelfde object wijzen.var- De compiler leidt het type zelf af uit de rechterkant.