Im letzten Beitrag habe ich Coding Guidelines Hinweise für besseren Code für LINQ versprochen.
Bevor wir allerdings dazu kommen ist es angebracht, zu definieren, worum es eigentlich geht: Was ist mit “LINQ” bzw. “Language Integrated Query” gemeint?
Dazu gibt es tatsächlich sehr unterschiedliche Auffassungen, daher macht diese Klärung durchaus Sinn.
Die übliche Einführung von LINQ beginnt immer mit der Darstellung einer Abfrage in Query-Syntax, z.B.:
1: var numQuery =
2: from num in numbers
3: where (num % 2) == 0
4: select num;
Auch die allermeisten Beispiele von Microsoft bedienen sich der Query-Syntax.
Das führt dann gelegentlich zu der Idee, dass LINQ gleichbedeutend mit der Verwendung der Schlüsselwörter from, where, select und so weiter sei. Die C# Coding Guidelines von Aviva bauen gar auf dieser Ansicht auf und definieren genau dazu eine Regel:
AV2220 Avoid LINQ for simple expressions
Rather than
var query = from item in items where item.Length > 0;
prefer using the extension methods from the System.Linq namespace.
var query = items.Where(i => i.Length > 0);Since LINQ queries should be written out over multiple lines for readability, the second example is a bit more readable.
(Hervorhebungen von mir.)
Als ob die zweite Darstellung kein LINQ wäre…
Um’s ganz deutlich zu sagen:
LINQ ist mehr, als die Verwendung von ein paar Schlüsselwörtern!
Zu LINQ gehören…
- Diverse Sprachbestandteile und unterstützende Interfaces
- Bibliotheken
- Theoretischer Unterbau
Sprachbestandteile
Zunächst ist herauszustellen, dass Query-Syntax und Method-Syntax (also der Verwendung entsprechender Extension Methods) als äquivalent – also beide als valides LINQ – anzusehen. Microsoft ist da selbst ziemlich deutlich:
“[…] the query syntax must be translated into method calls for the .NET common language runtime (CLR) […] You can call them directly by using method syntax instead of query syntax.”
Daneben hat es einen ganz praktischen Grund, die Method-Syntax nicht herabzuwürdigen: Die Schlüsselwörter der Query-Syntax bieten nur eine begrenzte Menge an Möglichkeiten und sind nicht erweiterbar. Abfragemöglichkeiten die darin nicht vorgesehen sind kann man daher nur über die Method-Syntax erreichen.
Beispiele dazu gab und gib es zur Genüge: Skip() und Take() um Ausschnitte des Resultsets auszuwählen, First() und Last() um einzelne Werte zu entnehmen, Aggregatfunktionen wie Sum(), komplexere Sortierungen, Umwandlungen mit ToArray(), und so weiter.
Damit haben wir dann die Extension Methods für IEnumerable von Enumerable im Boot.
Aber auch die Einschränkung darauf wäre zu kurz gegriffen, denn damit würden Querable and ParallelEnumerable unter den Tisch fallen. Also sind wir bei Extension Methods als generelles Sprachmittel (wenn auch für einen speziellen Anwendungsbereich) angelangt.
Auf Ebene der Sprachmittel kommen dann noch einige Dinge hinzu, die mit LINQ zusammenspielen, teilweise wegen LINQ überhaupt erst in C# aufgenommen wurden:
- Query-Operatoren (from, where, etc.)
- Implizite Typisierung (var)
- Objekt- und Listeninitialisierer
- Anonyme Typen
- Extension Methods
- Lambdas und Expression Trees
- Auto-Implemented Properties
- Nur für VB.NET: XML Literale
Nicht mit LINQ zusammen eingeführt, aber mittelbar damit zusammenhängend sind außerdem:
- Anonyme Delegates
- Generics (inkl. Type Inference)
- Iteratoren (yield)
Teilweise werden diese Sprachmittel durch Interfaces, Idiome und Basisimplementierungen in der BCL unterstützt. IEnumerable und Enumerable sind sicher die hervorstechendsten Beispiele.
Bibliotheken
Auf der anderen Seite kommt dann noch die Unterstützung durch Bibliotheken hinzu, um diverse Datenquellen verfügbar zu machen. Anders ausgedrückt, die Umsetzung von LINQ-to-XY in Form von LINQ-Providern. Besondere Bedeutung haben hier LINQ-to-Objects als kanonische Implementierung und für VB.NET LINQ-to-XML, weil es direkt vom Compiler unterstützt wird.
Theorie
Ein wichtiger Punkt, der gerne vergessen wird: LINQ ist eine Spielart funktionaler Programmierung, was dem Ganzen einen soliden theoretischen Unterbau gibt. Dazu zählen zum Beispiel zu folgende Themen:
- Deferred execution (msdn, Wes, Charlie, so)
- Lambdas (msdn C#, msdn C++)
- Closures (wikipedia, so1, so2)
- Immutability (Wes, Eric)
- Currying (Wes, so)
- Monads (so, so2)
- No nulls please (wikipedia, F#)
Wer hier tiefer einsteigen will, dem sei F# empfohlen.
Fazit
Damit haben wir das theoretische Fundament, nicht unerhebliche Teile des C#/VB.NET-Sprachumfangs, Interfaces und Klassen die das unterstützen, sowie weitere Bibliotheken für Datenquellen im Boot. Und das zudem in einem flexiblen, offenen System, denn Extension Methods oder LINQ Provider lassen sich nach Belieben ergänzen.
Das ist LINQ – nicht ein paar SQL-artige Schlüsselwörter.
PS: Bitte keine Irritationen wegen der wiederholten Erwähnung von VB.NET. Das war das letzte mal, versprochen 😉
Sie sehen gerade einen Platzhalterinhalt von Facebook. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von Instagram. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr InformationenSie sehen gerade einen Platzhalterinhalt von X. Um auf den eigentlichen Inhalt zuzugreifen, klicken Sie auf die Schaltfläche unten. Bitte beachten Sie, dass dabei Daten an Drittanbieter weitergegeben werden.
Mehr Informationen