Bills Neunte

… Noch deutlich wird dies natürlich
bei Klassentypen. Der Befehl

Dim P = New Person()

führt zwar auch bei VB8 dazu, dass P den
Typ Person erhält, bei VB 9 enthält die
Auswahlliste der IDE dank Typinferenz
bereits die Mitglieder der Person-Klasse.
Die neue Typinferenz dient aber weniger
dazu, die Deklaration von Variablen
zu vereinfachen, ohne sie wären LINQ-Abfragen
nicht so elegant möglich.

Die folgende kleine Schleife kann in Visual
Basic 8.0 nicht funktionieren, da die Variable
P nicht deklariert wird:

Dim Prozesse = Process.GetProcesses
For Each P In Prozesse
COnsole.WriteLine(P.ProcessName)
Next

Bei VB 9 wird sie nicht nur fehlerfrei kompiliert,
nach der Eingabe eines Punktes
auf die Variable P folgend, erscheinen die
Mitglieder der Process-Klasse in der Auswahlliste
(Abb. 2). P ist also typisiert.

Eine weitere Komforteinrichtung sind
die neuen Objektinitialisierer, die in vielen
Fällen den Konstruktor überflüssig
machen. Besitzt eine Klasse Person die Eigenschaften
Name und Alter lässt sie sich
bei VB 9 wie folgt instanziieren:

Dim P = New Person With {.Name = "Herbert", .Alter = 66}

Das ist wirklich sehr praktisch (die Möglichkeit,
Properties vereinfacht ohne Angabe eines privaten Feldes definieren zu können gibt es, anders als bei C# 3.0, aber
nicht), zumal es auch mit Arrays (aber leider
nicht mit Collections) funktioniert:

Dim Personen = New Person() {P, New Person With {.Name = "Günther", .Alter = 72}}

Auch hier sorgt Typinferenz dafür, dass
bei der Variablen Px bereits zur Entwurfszeit
die Mitglieder der Person-Klasse angeboten
werden:

For Each Px In Personen
Console.WriteLine(Px.Name)
Next

Doch das war noch nicht alles, auch mit
der folgenden Deklaration hat der Compiler
keine Probleme:

Dim P = New With {.Name = "Herbert", .Alter = 66}

Ist der Compiler vielleicht in der Lage, anhand
der Signatur der Property auf den Typ
der Klasse zu schließen? Soweit geht der
Komfort noch nicht. Hier sind die neuen
anonymen Typen im Spiel. Der Compiler
erstellt aus dem Nichts heraus einen neuen
Typ (mit einem „unaussprechlichen“
Namen), der mit den Eigenschaften Name
und Alter ausgestattet wird. Auch das ist
einer der Gründe, warum sich LINQ-Abfragen
so elegant formulieren lassen.

Über Erweiterungsmethoden (engl.
Extension Methods) kann eine (beliebige)
Klasse um statische Methoden erweitert
werden. Listing 1 enthält ein Modul,
das die Klasse Person um eine Funktion
CheckOldie() erweitert:

Mehr ist nicht zu tun, dass diese Methode auf Person-
Objekte nicht nur angewendet werden
kann, sondern sogar in der Auswahlliste
erscheint. Wichtig ist allerdings, dass das
Array Personen explizit deklariert wird.
Wird es wie folgt deklariert

Dim Personen() = {P1, P2}

funktioniert es nicht, auch wenn die Mitglieder
des Array danach als Person-
Objekte angezeigt werden. Auch Erweiterungsmethoden
sind weniger für den
Allgemeingebrauch bestimmt, sie sind,
neben Lambda-Ausdrücken, die zweite
Säule, auf der LINQ aufsetzt. Die neuen
SQL-Befehle, wie From, Where, Join oder
Group sind nichts anderes als Erweiterungsmethoden.

Lambda-Ausdrücke

Lamdba-Ausdrücke sind das neue Modewort
in Zusammenhang mit den zurzeit
populären funktionalen Programmiersprachen
wie F#, dabei geht ihr Ursprung
auf die 50er Jahre des letzten Jahrhunderts
zurück [3]. Bei VB 9 und C# 3.0 steht ein
Lambda-Ausdruck ganz einfach für Funktionscode,
der einer Variablen zugewiesen
oder auch direkt als Parameter übergeben
werden kann. Während C# diese Möglichkeit
mit den anonymen Delegaten bereits
mit der Version 2.0 bot, ist dieses Konzept
bei VB neu und auch nicht so weitreichend
wie bei C#. Bei VB 9.0 ist der Funktionscode,
der einer Variablen zugewiesen werden
kann, auf einfache Ausdrücke beschränkt,
Kontrollstrukturen sind (mit Ausnahme
des „neuen“ Iif-Operators) nicht erlaubt.
Listing 2 zeigt eine kleine Funktion Do-
TheOp
, der drei Parameter übergeben
werden: eine Lambda-Funktion, die mit
dem neuen Schlüsselwort Func definiert
wird, sowie zwei Integer.

Die Lambda-Funktion kann so definiert werden:

Dim DoDiv As Func(Of Integer, Integer, Integer) =
Function(p1 As Integer, p2 As Integer) p1 / p2

Ein wenig gewöhnungsbedürftig ist sicher
die Zweckentfremdung des Function-Befehls
(bei C# 3.0 gibt es stattdessen einen => Operator).

Für Funktionsvariablen gibt es zwei
Gründe. Zum einen führen sie zu noch mehr
Flexibilität (als ein Delegat), zum anderen
sind sie die Grundlage für das, was im
Rahmen einer LINQ-Abfrage z.B. über die
Where-Klausel übergeben wird. Auch dazu
ein kleines Beispiel. …

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.