Aufgaben-Python/courses/csharp/09_generics_und_constraints/README.md

53 lines
2.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# C# 09: Generics & Generic Constraints 🧬
Willkommen zu **Modul 09** des C# Masterkurses! In diesem Kapitel lernst du, wie du flexible, hochgradig wiederverwendbare und typsichere Datenstrukturen in C# 12 entwickelst.
---
## 💡 1. Das Wichtigste in Kürze
### Warum Generics?
Generics eliminieren die Notwendigkeit von Type-Casts und Boxing/Unboxing:
- **Typsicherheit:** Fehler werden bereits vom Roslyn-Compiler zur Build-Zeit erkannt.
- **Performance:** Wertetypen (wie `int`, `struct`) landen direkt auf dem Stack bzw. in typspezifischen Arrays – keine teure Heap-Allokation.
- **Code-Wiederverwendung:** Ein einzelner Algorithmus funktioniert für beliebig viele Typen.
### Generic Constraints (`where T : ...`)
Mit Constraints sagst du dem Compiler, welche Fähigkeiten der Typ `T` mitbringen muss:
```csharp
public class Repository<TEntity, TId>
where TEntity : class, IEntity<TId>, new()
where TId : notnull
{
// Hier können wir:
// - entity.Id aufrufen (durch IEntity<TId>)
// - TEntity instanziieren mit new TEntity() (durch new())
// - null zurückgeben (durch class)
}
```
### Der `Result<T>` Typ (Functional Error Handling)
Statt Ausnahmen für reguläre Fehlerflüsse zu werfen, kapselt `Result<T>` Erfolg oder Misserfolg:
```csharp
var result = Result<Customer>.Success(new Customer { Name = "Alice" });
if (result.IsSuccess)
{
Console.WriteLine($"Kunde geladen: {result.Value.Name}");
}
```
---
## 🎯 Teilziele in `Aufgabe.cs`
1. **TODO 1: `IEntity<TId>` Interface**
Definiere ein generisches Entity-Interface mit `TId Id { get; set; }`.
2. **TODO 2: `Result<T>` Wrapper-Klasse**
Implementiere einen unmodifizierbaren Result-Container mit `IsSuccess`, `Value`, `Error` sowie statischen Factory-Methoden `Success(T)` und `Failure(string)`.
3. **TODO 3: `InMemoryRepository<TEntity, TId>`**
Erstelle ein In-Memory Repository mit den Constraints `where TEntity : class, IEntity<TId>, new()` und `where TId : notnull`. Implementiere `Add`, `GetById`, `GetAll`, `Remove`, `Count` und `CreateDefault()`.
4. **TODO 4: Generische Hilfsmethoden**
Implementiere `Swap<T>(ref T a, ref T b)` und `FindMatches<T>(IEnumerable<T> items, Predicate<T> filter)`.