Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort zur 6. Auflage
1 Allgemeine Einführung in .NET
2 Grundlagen der Sprache C#
3 Das Klassendesign
4 Vererbung, Polymorphie und Interfaces
5 Delegates und Ereignisse
6 Strukturen und Enumerationen
7 Fehlerbehandlung und Debugging
8 Auflistungsklassen (Collections)
9 Generics – Generische Datentypen
10 Weitere C#-Sprachfeatures
11 LINQ
12 Arbeiten mit Dateien und Streams
13 Binäre Serialisierung
14 XML
15 Multithreading und die Task Parallel Library (TPL)
16 Einige wichtige .NET-Klassen
17 Projektmanagement und Visual Studio 2012
18 Einführung in die WPF und XAML
19 WPF-Layout-Container
20 Fenster in der WPF
21 WPF-Steuerelemente
22 Elementbindungen
23 Konzepte von WPF
24 Datenbindung
25 Weitere Möglichkeiten der Datenbindung
26 Dependency Properties
27 Ereignisse in der WPF
28 WPF-Commands
29 Benutzerdefinierte Controls
30 2D-Grafik
31 ADO.NET – Verbindungsorientierte Objekte
32 ADO.NET – Das Command-Objekt
33 ADO.NET – Der SqlDataAdapter
34 ADO.NET – Daten im lokalen Speicher
35 ADO.NET – Aktualisieren der Datenbank
36 Stark typisierte DataSets
37 Einführung in das ADO.NET Entity Framework
38 Datenabfragen des Entity Data Models (EDM)
39 Entitätsaktualisierung und Zustandsverwaltung
40 Konflikte behandeln
41 Plain Old CLR Objects (POCOs)
Stichwort

Download:
- Beispiele, ca. 62,4 MB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
Visual C# 2012 von Andreas Kühnel
Das umfassende Handbuch
Buch: Visual C# 2012

Visual C# 2012
Rheinwerk Computing
1402 S., 6., aktualisierte und erweiterte Auflage 2013, geb., mit DVD
49,90 Euro, ISBN 978-3-8362-1997-6
Pfeil 11 LINQ
Pfeil 11.1 Was ist LINQ?
Pfeil 11.1.1 Verzögerte Ausführung
Pfeil 11.1.2 LINQ-Erweiterungsmethoden an einem Beispiel
Pfeil 11.2 LINQ to Objects
Pfeil 11.2.1 Musterdaten
Pfeil 11.2.2 Die allgemeine LINQ-Syntax
Pfeil 11.3 Die Abfrageoperatoren
Pfeil 11.3.1 Übersicht der Abfrageoperatoren
Pfeil 11.3.2 Die »from«-Klausel
Pfeil 11.3.3 Mit »where« filtern
Pfeil 11.3.4 Die Projektionsoperatoren
Pfeil 11.3.5 Die Sortieroperatoren
Pfeil 11.3.6 Gruppieren mit »GroupBy«
Pfeil 11.3.7 Verknüpfungen mit »Join«
Pfeil 11.3.8 Die Set-Operatoren-Familie
Pfeil 11.3.9 Die Familie der Aggregatoperatoren
Pfeil 11.3.10 Quantifizierungsoperatoren
Pfeil 11.3.11 Aufteilungsoperatoren
Pfeil 11.3.12 Die Elementoperatoren
Pfeil 11.3.13 Die Konvertierungsoperatoren

11 LINQZur nächsten Überschrift


Rheinwerk Computing - Zum Seitenanfang

11.1 Was ist LINQ?Zur nächsten ÜberschriftZur vorigen Überschrift

LINQ (Language Integrated Query) ist eine Sprachergänzung von .NET, die mit .NET 3.5 eingeführt worden ist. Die Idee, die sich hinter LINQ verbirgt, ist, die Abfrage von Daten aus verschiedenen Datenquellen zu vereinfachen. Zu diesem Zweck stellt LINQ ein Modell zur Verfügung, mit dem einheitlich auf Daten aus verschiedensten Datenquellen zugegriffen werden kann, beispielsweise auf SQL-Datenbanken, auf XML-Dokumente und .NET-Auflistungen. Das Besondere ist dabei, dass Abfragen direkt als Code in C# oder andere .NET-Sprachen eingebunden werden können und nicht nur wie bisher als Zeichenfolge. Infolgedessen muss man also nicht mehr zwangsläufig SQL lernen, um Datenbanken abzufragen, oder XML Query, um Daten aus einem XML-Dokument zu lesen.

Die Syntax von LINQ ähnelt verblüffend den Abfragebefehlen von SQL, und so sind auch in LINQ Sprachelemente wie select, from oder where zu finden. Ein weiterer Vorteil von LINQ ist, dass dieses Abfragemodell als Teil der Sprache kompiliert werden kann und damit von IntelliSense unterstützt wird. Anders als etwa bei SQL-Abfragen, die erst zur Laufzeit ausgeführt werden, können Fehler so viel schneller gefunden werden.

Das folgende Beispiel soll Ihnen einen ersten Eindruck von LINQ vermitteln.

// Beispiel: ..\Kapitel 11\FirstLINQSample
class Program
{
static void Main(string[] args)
{
Person[] persons = {
new Person { Name = "Meier", Age = 34 },
new Person { Name = "Müller", Age = 51 },
new Person { Name = "Schmidt", Age = 30 },
new Person { Name = "Fischer", Age = 25 },
new Person { Name = "Schulz", Age = 67 },
};
var query = from pers in persons
where pers.Age >= 50
select pers;
foreach (var item in query)
Console.WriteLine("{0,-8}{1}", item.Name, item.Age);
Console.ReadLine();
}
}
class Person
{
public string Name { get; set; }
public int Age { get; set; }
}

Listing 11.1 Beispielprogramm »FirstLINQSample«

Im Beispiel wird ein Array aus mehreren Personen gebildet, das anschließend in der Weise gefiltert wird, dass nur alle Personen, die 50 Jahre alt sind oder älter, in die Ergebnismenge aufgenommen werden. Zur Bildung der Ergebnismenge wird ein LINQ-Ausdruck verwendet:

var query = from pers in persons
where pers.Age >= 50
select pers;

Listing 11.2 Abfragesyntax

Die von LINQ verwendete Syntax ähnelt der, die Sie vielleicht von SQL her kennen. An dieser Stelle sei bereits angedeutet, dass auch die Formulierung eines LINQ-Ausdrucks mit Erweiterungsmethoden möglich ist und zum gleichen Resultat führt:

var query = persons
.Where(p => p.Age >= 50)
.Select(p => p);

Listing 11.3 Erweiterungsmethodensyntax

Es spielt keine Rolle, woher die Daten in der Liste der Personen stammt: Es könnte sich zum Beispiel auch um die Ergebnismenge einer Datenbankabfrage handeln. LINQ ist in jedem Fall datenquellenneutral.

Die Einführung von LINQ mit C# 3.5 zwang das .NET-Entwicklerteam dazu, die .NET-Sprachen zu ergänzen. Dazu gehören Lambda-Ausdrücke, implizite Typisierung, Objektinitialisierer, anonyme Typen und Erweiterungsmethoden. Diese Sprachfeatures haben wir uns in den vergangenen Kapiteln bereits angesehen. Sie können LINQ-Abfragen in C# mit SQL Server-Datenbanken, XML-Dokumenten, ADO.NET-Datasets schreiben sowie jede Auflistung von Objekten abfragen. Es gibt allerdings dabei eine wichtige Bedingung zu beachten: Die Liste muss das Interface IEnumerable<T> implementieren.


Rheinwerk Computing - Zum Seitenanfang

11.1.1 Verzögerte AusführungZur nächsten ÜberschriftZur vorigen Überschrift

LINQ-Abfragen haben ein besonderes Charakteristikum. Sie werden nämlich nicht sofort ausgeführt, sondern erst, wenn die Ergebnismenge benötigt wird. Das könnte beispielsweise eine foreach-Schleife sein, innerhalb deren die Abfrageresultate verarbeitet werden.

Greifen Sie wiederholt auf die Ergebnismenge zu, wird die Abfrage jedes Mal erneut ausgeführt – die Ergebnismenge wird also nicht gecacht. Hat sich in der Zwischenzeit die Datenquelle geändert, erhalten Sie die aktualisierten Daten und profitieren von diesem Verhalten. Andererseits geht die erneute Ausführung natürlich auch zu Lasten der Leistung.

Ob das Verhalten der verzögerten Ausführung positiv oder eher negativ zu bewerten ist, hängt vom Einzelfall ab. In einer Anwendung, die mehrfach auf die Abfrageresultate zugreifen muss, können Sie mit den Methoden ToArray, ToList oder ToDictionary die Ergebnismenge zwischenspeichern. Keine Angst, Sie haben noch nichts verpasst, denn auf die genannten Methoden werden wir später noch eingehen.


Rheinwerk Computing - Zum Seitenanfang

11.1.2 LINQ-Erweiterungsmethoden an einem BeispielZur vorigen Überschrift

Das Fundament von LINQ sind die zahlreichen Erweiterungsmethoden, die im Namespace System.Linq definiert sind. Ehe wir uns eingehender mit LINQ beschäftigen, möchte ich Ihnen zeigen, wie eine LINQ-Erweiterungsmethode zustande kommt.

Dazu erzeugen wir ein String-Array mit mehreren Vornamen. Unser Ziel soll es sein, nur die Namen auszugeben, die einer bestimmten Maximallänge entsprechen. Für die Ausgabe soll eine Methode namens GetShortNames implementiert werden. Normalerweise würde die Überprüfung der Länge der einzelnen Namen in dieser Methode codiert. Um möglichst flexibel zu sein, wird die Überprüfung in eine andere Methode ausgelagert, die FilterName lauten soll. Der Methode GetShortNames wird neben dem Zeichenfolge-Array auch ein Delegat auf FilterName übergeben.

class Program {
delegate bool FilterHandler(string name);
static void Main(string[] args) {
string[] arr = { "Peter", "Uwe", "Willi", "Udo", "Gernot" };
FilterHandler del = FilterName;
GetShortNames(arr, del);
Console.ReadLine();
}
static void GetShortNames(string[] arr, FilterHandler del) {
foreach (string name in arr)
if (del(name)) Console.WriteLine(name);
}
static bool FilterName(string name) {
if (name.Length < 4) return true;
return false;
}
}

Listing 11.4 Filtern eines Zeichenfolgearrays

So weit funktioniert der Code einwandfrei. Was würden Sie aber machen, wenn Sie in einem anderen Kontext nicht die Namen selektieren wollen, die weniger als vier Buchstaben aufweisen, sondern beispielsweise mehr als sieben? Richtig, Sie würden eine weitere Methode bereitstellen, die genau das leistet. Und nun eine ganz gemeine Frage: Wie viele unterschiedliche Methoden wären Sie bereit zu implementieren, um möglichst viele Filter zu berücksichtigen?

Es geht auch anders, denn dasselbe Ergebnis wie in Listing 11.4 erreichen Sie, wenn Sie einen Lambda-Ausdruck benutzen. Der Code zur Überprüfung der Zeichenfolgelänge wird hierbei direkt in der Parameterliste von GetShortNames aufgeführt.

class Program {
static void Main(string[] args) {
string[] arr = { "Peter", "Uwe", "Willi", "Udo" };
GetShortNames(arr, name => name.Length < 4);
Console.ReadLine();
}
static void GetShortNames<T>(T[] names, Func<T, bool> getNames) {
foreach (T name in names)
if (getNames(name))
Console.WriteLine(name);
}
}

Listing 11.5 Filtern eines Zeichenfolgearrays mit einem Lambda-Ausdruck

Beachten Sie bitte den zweiten Parameter der Methode GetShortNames. Dessen Typ Func<T, bool> wird durch das .NET Framework bereitgestellt. Dabei handelt es sich um einen generischen Delegaten. Schauen wir uns dessen Definition an:

public delegate TResult Func<T, TResult>(T arg)

Der Delegat kann auf eine Methode zeigen, die einen Parameter entgegennimmt. Der generische Typ T beschreibt den Typ des Übergabeparameters, TResult den Typ der Rückgabe.

Im .NET Framework sind noch zahlreiche weitere Func-Delegaten vordefiniert. Damit werden Methoden beschrieben, die nicht nur einen, sondern bis zu 16 Parameter definieren. Eines haben aber alle Func-Definitionen gemeinsam: Der letzte generische Typparameter beschreibt immer den Datentyp der Ergebnismenge.

Vielleicht erinnern Sie sich: Ein Delegat kann auch durch einen Lambda-Ausdruck beschrieben werden. Das haben wir in Listing 11.5 durch die Übergabe von

Func<T, bool> getNames = name => name.Length < 4

genutzt. Der Übergabewert ist hier ein String, das Ergebnis der Operation ein boolescher Wert.

Wichtig ist, dass Sie erkennen, dass die Methode GetShortNames jetzt mit ganz unterschiedlichen Filtern aufgerufen werden kann. Vielleicht wollen Sie beim nächsten Mal alle Namen selektieren, die mit dem Buchstaben »H« beginnen. Kein Problem: Sie brauchen dazu keine weitere Methode zu schreiben und können die vorliegende benutzen, da der Lambda-Ausdruck in der Methode GetShortNames zur Auswertung herangezogen wird.

Rufen wir uns an dieser Stelle noch einmal das einführende LINQ-Beispiel des Listings 11.3 ins Gedächtnis zurück:

var query = persons
.Where(p => p.Age >= 50)
.Select(p => p);

Sieht die Filterung mit GetShortNames in Listing 11.5 nicht bereits sehr ähnlich der Filterung mit der Where-Methode aus?

Es gibt aber noch einen entscheidenden Unterschied: Wir übergeben der Methode GetShortNames die zu sortierende Liste als Argument. Besser wäre es, wir würden die Methode auf das Listenobjekt aufrufen. Dazu muss die Methode als Erweiterungsmethode definiert werden, wobei sich noch die Frage stellt, welche Klassen erweitert werden sollen und welchen Rückgabewert die Methode haben soll. Um die Allgemeingültigkeit der Methode sicherzustellen, legen wir fest, dass die Methode die Klassen erweitern soll, die IEnumerable<T> implementieren. Diese Schnittstelle soll auch gleichzeitig den Rückgabewert beschreiben, um damit zu gewährleisten, dass die Ergebnismenge in einer foreach-Schleife durchlaufen werden kann.

Diese Überlegungen erfordern es, dass der Code in Listing 11.5 an die Erweiterungsmethode GetShortNames angepasst werden muss. Bekanntlich müssen Erweiterungsmethoden in einer statischen Klasse definiert sein. Im folgenden Listing ist daher eine weitere Klasse definiert, die unsere Erweiterungsmethode enthält. Darüber hinaus wird der Bezeichner GetShortNames in Where geändert.

// Beispiel: ..\Kapitel 11\UserDefinedFilter
using System;
using System.Collections.Generic;
using System.Collections;
class Program {
static void Main(string[] args)
{
string[] arr = { "Peter", "Uwe", "Willi", "Udo" };
IEnumerable<string> query = arr.Where(name => name.Length < 4);
foreach (string item in query)
Console.WriteLine(item);
Console.ReadLine();
}
}
static class Extensionmethod {
// Erweiterungsmethode
public static IEnumerable<T> Where<T>(this IEnumerable<T> liste,
Func<T, bool> filter)
{
List<T> result = new List<T>();
foreach (T name in liste)
if (filter(name))
result.Add(name);
return result;
}
}

Listing 11.6 Beispielprogramm »UserDefinedFilter«

Das Resultat zur Laufzeit wird dasselbe wie vorher sein. Allerdings haben wir nun eine Erweiterungsmethode entwickelt, die nicht nur ein String-Array nach einer bestimmten Bedingung filtern kann, sondern jede x-beliebige Liste – vorausgesetzt, sie implementiert das Interface IEnumerable<T>. Tatsächlich funktioniert die LINQ-Erweiterungsmethode Where in derselben Weise. Werfen wir deshalb einen Blick auf die Definition der Methode von LINQ:

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

Der erste Parameter kennzeichnet Where als Erweiterungsmethode für alle Typen, die die Schnittstelle IEnumerable<T> implementieren. Der zweite Parameter ist ein Delegat, der im ersten generischen Parameter den in der Liste enthaltenen Typ beschreibt. Der zweite Typparameter gibt den Rückgabewert Boolean des Delegaten an.



Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Visual C# 2012

Visual C# 2012
Jetzt Buch bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchempfehlungen
Zum Rheinwerk-Shop: Professionell entwickeln mit Visual C# 2012






 Professionell
 entwickeln mit
 Visual C# 2012


Zum Rheinwerk-Shop: Windows Presentation Foundation






 Windows Presentation
 Foundation


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: C/C++






 C/C++


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo





Copyright © Rheinwerk Verlag GmbH 2013
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


Nutzungsbestimmungen | Datenschutz | Impressum

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern