Generics
Generics erlauben Code, der mit beliebigen Typen arbeitet, bei voller Typsicherheit (List<int>, Dictionary<string, Person>).
Console.WriteLine(Groesser(3, 9) + " " + Groesser("kiwi", "apfel") + " " + Groesser(2.5, 1.5));
var s = new Stapel<int>();
s.Push(1); s.Push(2); s.Push(3);
Console.WriteLine($"{s.Pop()} {s.Anzahl}");
var t = new Stapel<string>();
t.Push("a");
Console.WriteLine(t.Pop());
T Groesser<T>(T a, T b) where T : IComparable<T> => a.CompareTo(b) >= 0 ? a : b;
class Stapel<T>
{
private readonly List<T> _daten = [];
public int Anzahl => _daten.Count;
public void Push(T x) => _daten.Add(x);
public T Pop()
{
if (_daten.Count == 0) throw new InvalidOperationException("leer");
T x = _daten[^1];
_daten.RemoveAt(_daten.Count - 1);
return x;
}
}9 kiwi 2.5 3 2 a
Mit where schränkst du Typparameter ein: where T : class, struct, new(), IComparable<T>, Basisklasse.
LINQ: Abfragen auf Sammlungen
LINQ (Language Integrated Query) bietet Methoden zum Filtern, Umwandeln, Sortieren und Gruppieren von Daten. Das Ergebnis ist meist ein IEnumerable<T>:
var leute = new List<Person>
{
new("Mia", 17, "Köln"), new("Tom", 19, "Berlin"), new("Zoe", 21, "Köln"), new("Ben", 15, "Bonn"),
};
var volljaehrig = leute.Where(p => p.Alter >= 18).Select(p => p.Name).OrderBy(n => n).ToList();
Console.WriteLine(string.Join(", ", volljaehrig));
Console.WriteLine($"{leute.Average(p => p.Alter)} {leute.Max(p => p.Alter)} {leute.Count(p => p.Stadt == "Köln")}");
Console.WriteLine($"{leute.Any(p => p.Alter > 20)} {leute.All(p => p.Alter > 16)} {leute.FirstOrDefault(p => p.Alter > 100)?.Name ?? "keiner"}");
foreach (var gruppe in leute.GroupBy(p => p.Stadt).OrderBy(g => g.Key))
Console.WriteLine($"{gruppe.Key}: {string.Join(", ", gruppe.Select(p => p.Name))} (Ø {gruppe.Average(p => p.Alter):F1})");
var nachAlter = leute.OrderByDescending(p => p.Alter).ThenBy(p => p.Name).Take(2).Select(p => p.Name);
Console.WriteLine(string.Join(" ", nachAlter));
Console.WriteLine(string.Join(",", Enumerable.Range(1, 5).Select(x => x * x)));
Console.WriteLine(leute.ToDictionary(p => p.Name, p => p.Alter)["Zoe"]);
record Person(string Name, int Alter, string Stadt);Tom, Zoe 18 21 2 True False keiner Berlin: Tom (Ø 19.0) Bonn: Ben (Ø 15.0) Köln: Mia, Zoe (Ø 19.0) Zoe Tom 1,4,9,16,25 21
| Methode | Wirkung |
|---|---|
Where | filtern |
Select | umwandeln |
SelectMany | umwandeln und flachdrücken |
OrderBy, ThenBy, OrderByDescending | sortieren |
GroupBy | gruppieren |
Take, Skip | erste n / überspringen |
Distinct | Duplikate entfernen |
First, FirstOrDefault, Single | ein Element |
Any, All, Contains | prüfen |
Count, Sum, Average, Min, Max | Auswertungen |
Aggregate | falten |
ToList, ToArray, ToDictionary, ToHashSet | in Sammlung umwandeln |
Zip, Concat, Union, Intersect, Except | Mengen und Verbinden |
Verzögerte Ausführung
LINQ-Abfragen laufen erst, wenn du das Ergebnis brauchst (foreach, ToList, Count):
var zahlen = new List<int> { 1, 2, 3 };
var abfrage = zahlen.Where(x => { Console.Write($"[prüfe {x}]"); return x > 1; });
Console.WriteLine("Abfrage definiert");
zahlen.Add(4); // wird noch berücksichtigt!
Console.WriteLine(string.Join(",", abfrage));
var fest = zahlen.Where(x => x > 1).ToList(); // sofort ausgeführt, Ergebnis fixiert
zahlen.Add(5);
Console.WriteLine(fest.Count);Abfrage definiert [prüfe 1][prüfe 2][prüfe 3][prüfe 4]2,3,4 3
Abfragesyntax
Alternativ gibt es eine SQL-ähnliche Schreibweise:
var zahlen = Enumerable.Range(1, 10);
var ergebnis = from z in zahlen
where z % 2 == 0
orderby z descending
select z * z;
Console.WriteLine(string.Join(" ", ergebnis));100 64 36 16 4
Eigene Sequenzen mit yield
foreach (var f in Fibonacci().Take(10)) Console.Write(f + " ");
Console.WriteLine();
Console.WriteLine(string.Join(",", Teilbare(30, 7)));
IEnumerable<long> Fibonacci()
{
long a = 0, b = 1;
while (true) { yield return a; (a, b) = (b, a + b); } // unendlich, lazy
}
IEnumerable<int> Teilbare(int bis, int teiler)
{
for (int i = 1; i <= bis; i++) if (i % teiler == 0) yield return i;
}0 1 1 2 3 5 8 13 21 34 7,14,21,28
Merke
- Generics:
class Stapel<T>,T Methode<T>(T x);where T : ...schränkt ein - LINQ:
Where,Select,OrderBy,GroupBy,Sum,Any,ToListund mehr - Abfragen sind lazy: Sie laufen erst bei
foreach/ToList/Count yield returnerzeugt eigene Sequenzen- LINQ ersetzt viele handgeschriebene Schleifen, bleibt aber lesbar
Aufgabe
Gruppiere eine Liste von Bestellungen nach Kunde, berechne Summe und Anzahl je Kunde und gib die Top 3 aus.