OOD Handboek

6Generics

Een typeparameter T maakt een klasse of methode herbruikbaar voor elk type, met behoud van type-veiligheid. Je kent ze al: List<T>, Dictionary<K,V>.

// Generieke klasse (UML: Doos met T in stippelvakje)
public class Doos<T>
{
    public T Inhoud { get; set; }
    public Doos(T inhoud) { Inhoud = inhoud; }
    public void Toon() => Console.WriteLine($"De doos bevat: {Inhoud}");
}
var d1 = new Doos<string>("Boek");
var d2 = new Doos<int>(42);

// Generieke methode
public static void ToonWaarde<T>(T waarde)
    => Console.WriteLine($"Waarde: {waarde}");
Helper.ToonWaarde(42);  // T wordt int (afgeleid)

// Met constraint
public static T Grootste<T>(T a, T b) where T : IComparable<T>
    => a.CompareTo(b) > 0 ? a : b;
Uitleg

Een generieke klasse of methode werkt met een typeparameter T die je pas bij gebruik invult. Zo schrijf je één Doos voor strings, getallen of objecten, en blijft alles type-veilig. Met where eis je iets van T, zoals dat hij vergelijkbaar is.

Functies en keywords
CompareTo
Geeft negatief (eerder), 0 (gelijk) of positief (later) terug.
IComparable<T>
.NET-interface die zegt dat objecten onderling vergelijkbaar zijn.
where T :
Constraint: legt vast wat het type T minimaal moet kunnen of zijn.
<T>
Typeparameter: wordt pas bij gebruik ingevuld, bijvoorbeeld Doos<string>.
static
Hoort bij de klasse zelf, niet bij één object; gedeeld door alle objecten.
=>
Korte schrijfwijze voor een methode of property die één expressie teruggeeft; in LINQ ook de pijl van een lambda.
$"...{x}"
String-interpolatie: zet de waarde van x direct in de tekst.
var
De compiler leidt het type zelf af uit de rechterkant.
// Generiek logboek
public class Logboek<T> where T : LogItem
{
    private readonly List<T> _items = new();
    public void Voeg(T item) => _items.Add(item);
    public IReadOnlyList<T> FilterOpErnst(Ernst e)
        => _items.Where(i => i.Ernst == e).ToList();
    public IReadOnlyList<T> Chronologisch()
        => _items.OrderBy(i => i.Tijdstip).ToList();
}
Uitleg

Een generiek logboek dat alleen LogItems (of subklassen) accepteert, dankzij de constraint. Daardoor weet de compiler dat elk item een Ernst en Tijdstip heeft en kun je daarop filteren en sorteren met LINQ.

Functies en keywords
IReadOnlyList<T>
Alleen-lezen weergave van een lijst: wel lezen en doorlopen, niet toevoegen of verwijderen.
Where
LINQ: houdt alleen de elementen over die aan de voorwaarde voldoen.
OrderBy
LINQ: sorteert op de opgegeven eigenschap (oplopend).
ToList()
Maakt van het LINQ-resultaat een nieuwe List<T>.
where T :
Constraint: legt vast wat het type T minimaal moet kunnen of zijn.
<T>
Typeparameter: wordt pas bij gebruik ingevuld, bijvoorbeeld Doos<string>.
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.
new()
Target-typed new: het type wordt afgeleid uit de declaratie links.
List<T>
Lijst die automatisch groeit; toevoegen met Add, aantal met Count.
ConstraintT moet ...
where T : classeen referentietype zijn
where T : structeen waardetype zijn
where T : new()een lege constructor hebben
where T : Voertuig(sub)klasse van Voertuig zijn
where T : IComparable<T>die interface implementeren

ref: zonder ref krijgt een methode een kopie van een waardetype. void Verdubbel(ref int g) { g *= 2; } aanroepen met Verdubbel(ref x) wijzigt x zelf. out: methode moet de waarde vullen (zoals int.TryParse).