CodeGym /Kurse /C# SELF /Daten filtern mit Where

Daten filtern mit Where

C# SELF
Level 31, Lektion 2
Verfügbar

1. Einführung

Filtern bedeutet, aus einer Kollektion nur die Elemente auszuwählen, die einer bestimmten Bedingung entsprechen. Stell dir vor: In deiner Datenbank gibt es 10 000 Produkte, aber der Manager braucht „nur“ 12, die einem neuen, cleveren Kriterium entsprechen. Jedes Mal per Hand eine Schleife und zig Checks zu schreiben, macht echt keinen Spaß und der Code wird unlesbar. LINQ nimmt dir diesen Stress ab.

In echten Apps ist Filtern die häufigste Datenoperation: Wir zeigen dem User nur die Einträge, die ihn interessieren, „säubern“ Kollektionen von unerwünschten Elementen, machen Abfragen für Reports, Suche oder E-Mail-Versand. Bei Bewerbungsgesprächen kommen LINQ-Filter-Fragen ständig dran. Das Thema zu verstehen ist ein Muss für jeden .NET-Einsteiger.

2. Wir lernen die Methode Where kennen

Sinn und Funktionsweise

Die Methode Where ist eine LINQ-Extension-Method, die eine Funktion (oder ein Lambda-Expression) nimmt, die die Filterbedingung definiert. Sie gibt eine neue Sequenz zurück (ohne das Original zu verändern!), in der nur die Elemente sind, für die die Bedingung true zurückgibt.

Die Hauptsignatur:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, bool> predicate)

Keine Angst vor generics und komischen Begriffen. Wichtig ist erstmal die Grundidee: Where nimmt die Ausgangskollektion und eine Bedingung, die du vorgibst. In der Praxis ist das easy:

  • source — die Kollektion, die wir filtern (z.B. List<Product>)
  • predicate — Funktion/Bedingung (z.B. p => p.Price > 100)

Eine einfache Aufgabe zum Einstieg

Angenommen, wir haben eine Produktliste und wollen nur die auswählen, deren Preis größer als 100 ist. Früher hätte man eine foreach-Schleife geschrieben und die passenden Elemente manuell in eine neue Liste gepackt. Mit LINQ geht das in einer Zeile.

3. Filtern

Unsere Klasse Product und die Startkollektion

Im letzten Modul haben wir ungefähr so eine Produktklasse geschrieben:


class Product
{
    public string Name { get; set; }
    public double Price { get; set; }

    // Für hübsche Konsolenausgabe:
    public override string ToString()
    {
        return $"{Name} (Preis: {Price})";
    }
}

Angenommen, wir haben eine Produktliste:


var products = new List<Product>
{
    new Product { Name = "Brot", Price = 30 },
    new Product { Name = "Milch", Price = 87 },
    new Product { Name = "Käse", Price = 250 },
    new Product { Name = "Schokolade", Price = 130 }
};

Produkte mit Preis über 100 filtern mit Where


var expensiveProducts = products.Where(p => p.Price > 100);

foreach (var product in expensiveProducts)
{
    Console.WriteLine(product);
}

Was passiert unter der Haube:

  • Where geht alle Elemente der Liste products durch,
  • ruft für jedes die Funktion auf (hier: p => p.Price > 100),
  • wenn die Funktion true zurückgibt, kommt das Produkt in die neue Kollektion.

Ergebnis auf dem Bildschirm:

Käse (Preis: 250)
Schokolade (Preis: 130)

Achte drauf: Die Ursprungsliste products bleibt unverändert! LINQ zerstört deine Daten nicht.

4. Lazy Filtering (Deferred Execution)

Ein spannender und wichtiger Punkt: Das Ergebnis von Where wird erst berechnet, wenn du wirklich auf die Elemente zugreifst. Zum Beispiel, sobald die foreach-Schleife startet, „geht“ LINQ die Ursprungskollektion durch und filtert die Elemente on the fly. Wenn du das Ergebnis nicht nutzt, passiert gar nichts. Das nennt man verzögerte Ausführung (deferred execution).

Das bringt uns viele Vorteile:

  • Du kannst richtig lange Method-Chains bauen (z.B. filtern und sortieren) und erst beim ersten echten Zugriff wird alles ausgeführt.
  • Speicher sparen: Es gibt keine unnötigen Zwischenkollektionen.
  • Bei Bedarf kannst du die Ausführung abbrechen oder nach einer bestimmten Anzahl gefundener Elemente stoppen.

Visualisierung


Ursprungskollektion      —►   Where (Bedingung)   —►   Wir gehen nur die passenden Elemente durch
    
[ x ] [ x ] [ + ] [ + ]  —►   p.Price > 100      —►   [ + ] [ + ]

(x — Element erfüllt die Bedingung nicht, + — erfüllt sie)

5. Syntax-Varianten

Klassische Extension-Method (Method Syntax)

Diesen Stil nutzen wir schon:

var result = products.Where(p => p.Price > 100);

Alternative: Query Syntax

LINQ unterstützt auch eine Syntax, die wie SQL-Queries aussieht:


var result = from p in products
             where p.Price > 100
             select p;

Das Ergebnis ist das gleiche!
Welche Syntax du nimmst, ist Geschmackssache, aber method syntax (Punkt-Methoden) sieht man öfter, vor allem in echten Projekten und bei langen Method-Chains.

6. Komplexe Filterbedingungen

Mehrere Bedingungen

Du kannst logische Operatoren nutzen (&&, ||, !):


// Finde alle teuren Produkte außer "Schokolade"
var filtered = products.Where(
    p => p.Price > 100 && p.Name != "Schokolade"
);

Filtern nach String (Substring, Groß-/Kleinschreibung, Contains)


// Produkte, deren Name den Buchstaben "l" enthält
var lProducts = products.Where(p => p.Name.Contains("l"));

Achtung: Contains ist case-sensitiv! Wenn du „ohne Groß-/Kleinschreibung“ willst, geht das so:


var lProducts = products.Where(p => p.Name
    .ToLower().Contains("l")); // jetzt kommen "Milch" und "Schokolade" beide ins Ergebnis

Filtern über mehrere Kollektionen

Angenommen, du hast zwei Listen – Produkte und Zahlungen. Du kannst Produkte filtern, die in der Zahlungsliste vorkommen – dafür nutzt man aber besser Any und Join, dazu später mehr. Merke dir: LINQ kann auch noch viel komplexer filtern!

7. Nützliche Feinheiten

Verschachteltes Filtern und Method-Chains

Du kannst mehrere Filterstufen kombinieren, indem du Where mehrfach hintereinander aufrufst:


var filtered = products
    .Where(p => p.Price > 100)
    .Where(p => p.Name.StartsWith("Sch"));

Aber besser ist es, die Bedingungen in einem Where mit logischen Operatoren zu verbinden – das ist effizienter und der Code bleibt übersichtlicher.

Eingebaute Vergleicher und eigene Funktionen

Manchmal reichen die Standard-Operatoren nicht. Zum Beispiel willst du Strings ohne Groß-/Kleinschreibung und mit Culture beachten. Dann sind Vergleichsmethoden praktisch:


var rusProducts = products.Where(
    p => p.Name.StartsWith("sch", StringComparison.OrdinalIgnoreCase)
);

8. Filtern und Benutzereingaben

Probieren wir mal ein simples Filter-Command in der Praxis! Zum Beispiel fragen wir den User nach dem Mindestpreis und zeigen dann alle passenden Produkte.


Console.Write("Mindestpreis für das Produkt? ");
var minPriceStr = Console.ReadLine();
if (double.TryParse(minPriceStr, out double minPrice))
{
    var filtered = products.Where(p => p.Price >= minPrice);
    foreach (var product in filtered)
    {
        Console.WriteLine(product);
    }
}
else
{
    Console.WriteLine("Fehler: Keine Zahl eingegeben.");
}

Jetzt sieht unsere "Mini-App" schon fast wie ein Shop aus!

9. Typische Fehler und Stolperfallen bei Where

Beim Programmieren gibt’s wie im echten Leben Fallstricke. Das solltest du vermeiden.

Vergessen, ToList() oder ToArray() zu rufen

Das Ergebnis von Where ist kein List und auch kein Array! Es ist ein IEnumerable<Product>. Meist klappt das super in der foreach-Schleife, aber wenn du wirklich eine Kollektion brauchst (z.B. für Indexzugriff), vergiss nicht .ToList() oder .ToArray() zu rufen:


var filteredList = products.Where(p => p.Price > 100).ToList();

Wenn du das vergisst, bekommst du schnell Fehler wie "Collection was modified during enumeration" – vor allem, wenn du die Ursprungskollektion während der Iteration änderst.

Ändern der Ursprungskollektion

Da LINQ-Filterung verzögert ist, kann es zu Exceptions kommen, wenn du während der Iteration Elemente aus der Ursprungsliste entfernst. Besonders bei Multithreading oder wenn die Kollektion direkt beim Filtern geändert wird.

Null-Werte und Prädikate

Wenn die Kollektion null enthält und du im Prädikat auf ein Feld zugreifst, ohne zu prüfen, gibt’s ein NullReferenceException. Zum Beispiel:


var filtered = products.Where(p => p.Name.StartsWith("A"));

Wenn ein Element in products null ist, crasht der Code.

Tipp: Immer auf null prüfen, wenn das vorkommen kann:


var filtered = products.Where(p => p != null && p.Name.StartsWith("A"));
2
Aufgabe
C# SELF, Level 31, Lektion 2
Gesperrt
Filtern von Objekten nach mehreren Kriterien
Filtern von Objekten nach mehreren Kriterien
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION