Thomas Kramer

IT-COW | 3.0

"LINQ und Konsorten" Teil 1 & Sprachfeatures von C# 3.0

By Administrator at August 19, 2010 19:27
Filed Under: .net-Framework, 3.0, 3.5, C#, Webcast-Reviews

Ich beschäftige mich gerade mit LINQ, der einheitlichen Abfrage-Sprache von Microsoft, die auch einen O/R-Mapper beinhaltet - als Datenbank-Anwendungsentwickler komme ich natürlich nicht umhin mich damit zu befassen.

 

In Ermangelung eines Projekts mit dieser Technik wollte ich mich zuerst mit den Webcast-Serien von Microsoft zu dem Thema befassen -> Link. Mir ist (noch) kein OpenSource-Projekt bekannt das diese Technik einsetzt, daher nehme ich Hinweise dazu gerne entgegen.

 

Die Webcast-Reihe im MSDN zu LINQ umfasst acht Teile, dieser Eintrag wird daher noch erweitert und ergänzt werden. Die Webcasts wurden von Herrn Dariusz Parys, Technical Evangelist bei Microsoft, erstellt.

 

Im ersten Webcast wird ein Überblick über die Inhalte der gesamten Webcast-Reihe gegeben, die da wären:

 

  • LINQ to SQL
  • LINQ to Objects / LINQ to Datasets
  • LINQ to XML
  • LINQ to Entities
  • ADO.NET Data Services
  • Concurrency und Transaktionen
  • Verteilte Anwendungen mit LINQ

 

LINQ ist eine Neuerung des .net 3.5-Framework. Für LINQ wurden folgende Sprachfeatures ins .net-Framework integriert, zum Teil bereits mit Version 3.0:

 

  • Implicitly Typed Local Variables
  • Object & Collections Initializers
  • Extention Methods
  • Anonymous Types
  • Lambda Expressions
  • Auto-Implemented Properties
  • Partial Methods
  • Expression Trees

 

Implicitly Typed Local Variables

 

Zuerst wurde die Type inference erläutert, die in C# über die Implicitly Typed Local Variables erreicht werden, einem C# 3.0-Sprachfeature. Normalweise sieht eine Variablendeklaration in C# folgendermaßen (mit Zuweisung) aus:

 

string s1 = "Hello, World.";

 

Nun muss ab C# 3.0 der Typ nicht mehr angegeben werden, sondern es kann alternativ das Schlüsselwort var angewandt werden:

 

var s = "Hello, World.";

 

Aus der Zuweisung folgert der Compiler, das s eine Variable vom Typ string ist. Im Gegensatz zum Schlüsselwort dynamic kann sich der Datentyp nicht zur Laufzeit ändern, die Typsicherheit besteht demnach weiterhin. Das kann die Tipparbeit insbesondere bei generischen Datentypen verringern, im Allgemeinen sollte aber weiterhin der Typ explizit angegeben werden.

 

Auto-Implemented Properties

 

Gemäß Link ist dieses Sprachfeature ebenfalls mit C# 3.0 eingeführt worden. Eine solche Property sieht folgendermaßen aus:

 

public string Lastname
{
  get;
  set;
}

 

Der Member, der intern zum Speichern des Nachnamens verwendet wird, wird so automatisch erzeugt und ist im Quellcode nicht sichtbar.

 

Object Initializers

 

Im Webcast wurde dieses Beispiel dafür gewählt, vorher wurde eine Klasse Person mit den Properties Firstname, Lastname und Age erstellt.

 

Person p = new Person
{
  Firstname = "Dariusz",
  Lastname = "Parys",
  Age = 36
}

 

In diesem Beispiel wird die Klasse Person instanziiert (mit dem Standard-Konstruktor), den Properties dieser Klasse die Eigenschaften "Dariusz", "Parys" und 36 zugewiesen, und anschließend der Variablen p übergeben.

 

Bei Object Initializers handelt es sich wieder um ein C# 3.0 - Sprachfeature -> MSDN-Link. Geschweifte Klammern werden hier zur Übergabe benutzt, keine runden wie bei Eingaben für Konstruktoren üblicherweise.

 

An der Stelle im Webcast zeigte der Mann den IL-Disassembler vom .net-SDK, dessen Standort im Dateisystem er erst suchen musste... hier würde ich ihm das Programm Everything empfehlen, das im Gegensatz zu anderen Dateiensuch-Programmen nicht erst zeitaufwendig einen Index erstellen muss, sondern in Echtzeit indexiert und auch suchen kann.

 

Extension Methods

 

Gemäß Link handelt es sich hierbei wieder um ein C# 3.0-Sprachfeature. Über Extension Methods können vorhandene Klassen um Funktionen erweitert werden, ohne diese in die Klasse selbst hinein zu schreiben. Das geschieht über das Schlüsselwort this in der Methodendeklaration einer Klasse. Ein sehr einfach anzuwendendes Feature, das Beispiel im Webcast sah folgendermaßen aus:

 


public static class MeineErweiterungenfürPerson
{
  public static string SagHallo( this Person p)
  {
     return string.Format( "Hallo von {0}", p.Lastname );
  }
}

 

... (this Person p) besagt in diesem Fall, das die Methode SagHallo zur Klasse Person hinzugefügt wird bzw. über diese aufrufbar ist. Meines Erachtens ist das hauptsächlich sinnvoll wenn man den Quellcode der Originalklasse nicht zur Verfügung hat, ansonsten sollte man die neue Funktion natürlich direkt in die zugehörige Klasse verfrachten.

 

Lambda-Expressions

 

Zuerst hatte er eine Personenliste erstellt:

 

List<Person> listOfPersons = new List<Person> {new Person{ Lastname="Walzenbach", Firstname="Daniel", Age=32}, p};

 

Diese beinhaltet zwei Personen, Daniel Walzenbach wurde namentlich direkt angegeben (Object Initializers), und als zweite Person die Variable p.

 

Dann gestaltete er eine übliche foreach-Abfrage mit der nach einer Person in dieser Liste gesucht werden sollte, die jünger als 33 Jahre alt ist. Anschließend hatte er das entsprechend für eine Lambda-Abfrage umfunktioniert:

 

var result = listOfPersons.Where<Person>( pp => pp.Age <33 );

 

Die Syntax liest sich ähnlich wie bei SQL, die Variable pp kann hier frei vergeben werden und entspricht der Iterator-Variablen bei einer foreach-Schleife.

 

Bei Lambda-Expressions handelt es sich wieder um ein C# 3.0-Sprachfeature. Eine gute deutschsprachige Anleitung dazu ist auch hier zu finden. Weiterer Link.... der dazugehörige MSDN-Eintrag ist hier verlinkt: Link.

 

>>LINQ to Objects-Abfrage

 

An der Stelle kam er im Webcast endlich auf typische LINQ-Abfragen zu sprechen. Die oben aufgeführte Lambda-Abfrage, umgemünzt auf eine LINQ to Objects-Abfrage, sieht folgendermaßen aus:

 

var result = from pp in listOfPersons
                 where pp.Age <33
                 orderby pp.Lastname descending
                 select pp;

 

Die Notation erinnert hier noch stärker an SQL. Diese Abfrage kann auf alle Klassen angewandt werden, bei denen das Interface IEnumerable implementiert wurde.

 

Anonyme Typen

 

Ergänzend hat er dann noch die anonymen Typen erklärt, welche wieder ein C# 3.0 - Sprachfeature darstellen.

 

var result = from pp in listOfPersons
                 where pp.Age <33
                 orderby pp.Lastname descending
                 select new´
                 {
                     Vorname=pp.Firstname,
                     Nachname=pp.Lastname
                 };

 

Mit diesem Beispiel beinhaltet result anschließend nicht mehr die Properties Firstname und Lastname, sondern Vorname und Nachname. Mit anonymen Typen können auch quasi anonyme Klassen erstellt werden, siehe das Beispiel im MSDN:

 

var v = new { Amount = 108, Message = "Hello" };

 

Hier wird noch nichtmal eine Klasse angegeben, meines Erachtens sollte man so etwas aber nur für einfachere Dinge verwenden, ansonsten würde ich schon eine Klassendefinition im Quelltext sehen wollen. Weiterer Link zu anonymen Typen hier.

 

Das war LINQ to Objects, zuletzt hatte er noch erwähnt das die Syntax bei LINQ to SQL genauso aussieht. Weiterer Link zu LINQ: Link.

 

Fortsetzung mit Teil zwei der Webcast-Reihe: Link.

 

Ergänzung 9.4.2011: Ein besserer Überblick über die verschiedenen LINQ-Technologien ist nun in meinem Review zu Teil fünf zu finden: Link. Das entspricht dem Aufbau dieser Webcast-Reihe; eventuell wäre man auf die Architektur besser im ersten oder zweiten Teil eingegangen, hätte dann aber möglicherweise auch Einsteiger verschreckt.

 

Monats-Liste