Seit einiger Zeit ging es in meinen Projekten immer mehr um gute Lesbarkeit des Codes, da die Wartbarkeit der Projekte wichtig war.
Oftmals musste ich in Listen wühlen und bestimmte Items (<T>) bzw. Indices herausfinden.
Früher tat ich das in einfachen for/foreach-schleifen und einer if-Abfrage:

    foreach (Person item in myList)
   {
      if (item.Age == 20)
      {
          n = myList.IndexOf(item);
          break;
      }
   }    

Codemäßig ist dies aber wirklich – nennen wir es mal suboptimal gelöst. (Klar können wir alles gruppieren etc…)

Auf der Suche nach einem besseren Weg meine Arrays und Listen zu durchlaufen fand ich schließlich LINQ im Namespace System.LINQ.

LINQ ist erst ab .NET 3.5 verfügbar, wer LINQ davor nutzen will, kann LINQBridge nutzen, ein Framework, welches alle Standardqueryoperatorionen in .NET Framework 3.5’s Enumerable Klasse reimplementiert.

Ich werde hier nur auf die Query Expressions eingehen. Man kann aber auch Lambda Expressions nutzen, dazu aber ein anderes Mal mehr.

Nun verwenden wir also den Namespace mit der using-Direktive:

 using System.LINQ; 

Vorweg: SQL Wissen ist hier sehr praktisch!

Warum seht ihr hier:

             IEnumerable myQuery =  from m in myFiles
                                    select m.extension; 

Syntaktisch ist LINQ sehr an SQL angelehnt, es wird spezifiert von was die Daten kommen (from) und was ausgegeben wird (select).

In unserem Beispiel habe ich also eine List myFiles und frage das Attribut extension des Objektes T in der Liste ab.

Der Typ IEnumerable muss hier genutzt werden, denn:
   1. Die Abfrage hat als Quelle eine Liste, welche IEnumerable implementiert.
   2. Die Abfrage selbst gibt ein IEnumerable zurück.

Wenn man faul ist, kann man auch implizit deklarieren, mit var.
Der Compiler führt dann die explizite Deklaration durch.

Wer sich in SQL auskennt wird sich jetzt sicher fragen, wie es mit Bedingungen aussieht.
Klar, die gibt es auch. Sonst wäre LINQ wirklich nutzlos:

             IEnumerable myQuery =  from m in myFiles
                                    where m.extenseion == ".txt"
                                    select m.extension; 

Hier ist zu beachten, dass immer noch der C#-Syntax gilt – also Vergleichsoperatoren von C# nutzen!

Zudem gibt es natürlich auch Gruppier- und Ordnungsfunktionen:

             IEnumerable myQuery =  from m in myFiles
                                    where m.extenseion == ".txt"
                                    orderby m.extension
                                    select m.extension; 

Hier wird also zusätzlich noch alphabetisch geordnet. Ascending/Descending sind natürlich verfügbar.

  orderby m.extension ascending 
  orderby m.extension descending 

Zu guter letzt hat Microsoft auch hier ein tolles Feature aus SQL übernommen, nämlich Joins.
Vom Grundprinzip ist es wieder SQL gleich:

 join "Objekthier" on "Key1" equals "Objekthier.Key2" 

Beispiel:

 join file in FileList on extension.Id equals file.Id 

Ein vollständiges LINQ-Query sieht also beispielweise so aus:

IEnumerable query = (from file in fileList
join ext in extensionList on file.Id equals ext.Id 
where ext.Id == 1 && file.ReadOnly == false
orderby ext.extension ascending
select file); 

Aber Achtung:

Das gejointe Objekt (file) muss sich auf der rechten Seite des equals-Statements befinden, ansonsten schmeißt der Compiler folgenden Fehler:

Name model is not in scope on the left side of equals. Consider swapping the expression on the either side of equals.

WARNUNG: LINQ ist bis zu zwei mal langsamer als for-Schleifen und dient nur zum Aufbau strukturierteren Codes. Meistens ist die Abfrage performancemäßig vergleichbar mit einer foreach-Schleife