4.6 Anonyme Klassen 

Wenn Sie für einen kurzen Codeabschnitt ein paar Daten zusammenfassen wollen, die Sie an anderer Stelle in dieser Zusammenstellung nicht mehr brauchen, ist es ein enormer Aufwand, dafür eine eigene Klasse zu definieren. Daher bietet Visual Basic die Möglichkeit, ad hoc ein Objekt mit Daten von einer Klasse zu erzeugen, die der Compiler automatisch aus den Daten ableitet und benennt. In den beiden folgenden Syntaxvarianten sind frei wählbare Teile kursiv gesetzt und optionale Teile in eckigen Klammern. Der Modifikator Key sorgt dafür, dass die Eigenschaft schreibgeschützt ist. Bitte beachten Sie das Fehlen der As-Klausel.
Dim objekt = New With { [Key] .Zustand = Wert [, <weitere Zustände/Werte>]} |
Hinweis |
Wenn die Compileroption Infer auf Off gestellt ist oder das Objekt auf Typebene definiert ist, muss eine As-Klausel spezifiziert werden, was Ihnen Kopfschmerzen bereiten wird (siehe Abschnitt 4.6.1, »Automatische Namen«). |
Als Beispiel fassen wir ein paar Daten zum Kölner Dom in der Variablen KölnerDom zusammen. Die »unveränderlichen« Daten werden durch den Modifikator Key zu schreibgeschützten Eigenschaften. Daher würde die auskommentierte Zeile zu einem Compilerfehler führen. Wie die Eigenschaft Adresse zeigt, kann auf bereits initialisierte Eigenschaften zurückgegriffen werden. Ist das Objekt einmal erzeugt, wird es genauso verwendet wie ein Objekt einer »normalen« Klasse.
'...\Datentypen\AnonymeKlassen\Prinzip.vb |
Option Strict On
Namespace Datentypen
Module Prinzip
Sub Test()
Dim KölnerDom = New With { _
.Domprobst = "Henrichs", _
Key .Straße = "Domkloster", Key .Nummer = 4, _
Key .Adresse = .Straße & " Nummer " & .Nummer _
}
KölnerDom.Domprobst = "Feldhoff"
'KölnerDom.Nummer = 12
Console.WriteLine("Der Dom hat die Adresse {0}.", KölnerDom.Adresse)
Console.WriteLine("Derzeitiger Probst ist {0}.", KölnerDom.Domprobst)
Console.ReadLine()
End Sub
End Module
End Namespace
Hinweis |
Eine Eigenschaft einer anonymen Klasse kann eine andere nur nutzen, wenn sie bereits initialisiert wurde. Zirkelbezüge sind verboten. |
Die Ausgabe bestätigt den korrekten Zugriff:
Der Dom hat die Adresse Domkloster Nummer 4.
Derzeitiger Probst ist Feldhoff.
Hinweis |
Die Datenabfrage mit LINQ macht implizit sehr viel Gebrauch von anonymen Klassen (siehe Abschnitt 6.4, »LINQ«). |
4.6.1 Automatische Namen 

Schauen wir uns einmal an, welchen Klassennamen der Compiler aus Ihren Angaben für die anonyme Klasse generiert. Dabei gibt es zwei Automatismen:
- Qualifizierte Werte ohne Eigenschaftsspezifikation erzeugen einen Eigenschaftsnamen.
- Der Klassenname wird durch die Typen und die Reihenfolge der Eigenschaften kontrolliert.
Das nächste Codefragment analysiert die automatisch generierten Namen. Dazu werden mit New With drei Objekte anonymer Klassen erzeugt und deren Klassenname sowie Eigenschaften in der Methode Info() ausgegeben.
'...\Datentypen\AnonymeKlassen\Namen.vb |
Option Strict On
Imports System.Reflection
Namespace Datentypen
Module Zimmer
Public Nr As Integer = 1717, Preis As Integer = 3000
End Module
Module Namen
Sub Test()
Dim hb = New With { Nr, .Gast = "Howard Bannister"}
Dim jm = New With { Nr, .Gast = "Judy Maxwell"}
Dim eb = New With {Key Nr, .Gast = "Eunice Burns"}
Dim fl = New With {.Gast = "Frederick Larrabee", Key Nr}
Info(hb.Gast, hb.GetType())
Info(jm.Gast, jm.GetType())
Info(eb.Gast, eb.GetType())
Info(fl.Gast, fl.GetType())
Console.ReadLine()
End Sub
Sub Info(ByVal gast As String, ByVal typ As Type)
Console.Write("{0,16}: Typ {1} + Felder < ", gast, typ.Name)
For Each p As PropertyInfo In typ.GetProperties()
Console.Write(p.Name & If(p.CanWrite, " ", "(nur lesen) "))
Next
Console.WriteLine(">")
End Sub
End Module
End Namespace
Der Vergleich der beiden ersten Ausgaben zeigt, dass für die beiden ersten Objekte dieselbe Klasse verwendet wird, da diese Objekte in den Datentypen der Eigenschaften komplett übereinstimmen. Bereits ein Schreibschutz mit Key oder ein Vertauschen der Reihenfolge macht das Typrecycling unmöglich, wie die beiden letzten Ausgaben mit unterschiedlichen Typnamen zeigen:
Howard Bannister: Typ VB$AnonymousType_0`2 + Felder < Gast Nr >
Judy Maxwell: Typ VB$AnonymousType_0`2 + Felder < Gast Nr >
Eunice Burns: Typ VB$AnonymousType_1`2 + Felder < Gast Nr(nur lesen) >
Frederick Larrabee: Typ VB$AnonymousType_2`2 + Felder < Gast Nr(nur lesen) >
Hinweis |
Der kryptische Klassenname ist das, was Sie in einer As-Klausel angeben müssten. |
4.6.2 Schlüssel und Equals 

Beim Test auf Gleichheit von Objekten anonymer Typen werden nur die mit Key gekennzeichneten schreibgeschützten Eigenschaften berücksichtigt. Ebenso wird bei der Berechnung des Hashcodes verfahren, der zum Beispiel oft zum Sortieren und Prüfen auf Dubletten von Mengen verwendet wird. Damit wird die Wahl des Namens Key für den Modifikator verständlicher. Das folgende Codefragment testet diese eingeschränkte Berücksichtigung der Eigenschaften anhand politischer Parteien. Die ersten beiden Politiker sind in derselben Partei, der dritte ist in einer anderen. Gleichheit der Objekte und Hashcodes wird für Politiker derselben und unterschiedlicher Parteien getestet.
'...\Datentypen\AnonymeKlassen\Gleichheit.vb |
Option Strict On
Namespace Datentypen
Module Gleichheit
Sub Test()
Dim Putin = New With { _
Key .Partei = "Einiges Russland", .Person = "Wladimir Putin"}
Dim Medwedew = New With { _
Key .Partei = "Einiges Russland", .Person = "Dmitri Medwedew"}
Dim Sjuganow = New With { _
Key .Partei = "Kommunisten", .Person = "Gennadi Sjuganow"}
Console.WriteLine("Putin gleich Medwedew {0}", Putin.Equals(Medwedew))
Console.WriteLine("Putin gleich Sjuganow {0}", Putin.Equals(Sjuganow))
Console.WriteLine("Hash: Putin = Medwedew {0}", _
Putin.GetHashCode() = Medwedew.GetHashCode())
Console.WriteLine("Hash: Putin = Sjuganow {0}", _
Putin.GetHashCode() = Sjuganow.GetHashCode())
Console.ReadLine()
End Sub
End Module
End Namespace
Da der Name des Politikers nicht mit Key gekennzeichnet ist, wird er nicht beim Vergleich berücksichtigt und Politiker derselben Partei werden als gleich angesehen. Dies gilt auch für den Hashcode der Politiker:
Putin gleich Medwedew True
Putin gleich Sjuganow False
Hash: Putin = Medwedew True
Hash: Putin = Sjuganow False
Hinweis |
Wenn eine Veränderung nicht unbedingt nötig ist, sollten alle Eigenschaften einer anonymen Klasse mit Key gekennzeichnet werden, um bei Vergleichen und Hashcodes alle Eigenschaften zu berücksichtigen. |
4.6.3 Innere anonyme Klassen 

Objekte anonymer Klassen dürfen auch als Werte innerhalb von Objekten anonymer Klassen verwendet werden, ganz analog zu anderen Klassen (siehe Abschnitt 3.8, »Innere Klassen«). Das nächste Codefragment zeigt einen Pfarrer mit »inneren Werten«.
'...\Datentypen\AnonymeKlassen\InnereAnonymeKlassen.vb |
Option Strict On
Namespace Datentypen
Module InnereAnonymeKlassen
Sub Test()
Dim Pfarrer = New With {.Werte = New With {.Ehrlich = True}}
Console.WriteLine("Pfarrer ist ehrlich: {0}", Pfarrer.Werte.Ehrlich)
Console.WriteLine("Wertetyp: {0}", Pfarrer.Werte.GetType().Name)
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt, dass innere anonyme Klassen keine Besonderheiten aufweisen:
Pfarrer ist ehrlich: True
Wertetyp: VB$AnonymousType_2`1
4.6.4 Generierter Code 

Durch die Deklaration New With erzeugt der Compiler automatisch eine neue Klasse mit der Funktionalität, die zur Verwendung der Eigenschaften gebraucht werden. So betrachtet sind anonyme Klassen »nur« ein Compilertrick und keine echte Erweiterung der Sprache Visual Basic. Die Deklaration
Dim käfig = New With {Key .Tierart = "Katze", .Anzahl = 4}
erzeugt eine Klasse mit den folgenden Signaturen:
Friend NotInheritable Class VB$AnonymousType_0(Of String, Integer)
Public Overloads Function _
Equals(ByVal val As VB$AnonymousType_0(Of String, Integer)) As Boolean
Public Overrides Function Equals(ByVal obj As Object) As Boolean
Public Overrides Function GetHashCode() As Integer
Public Overrides Function ToString() As String
Public Property Anzahl() As Integer
Public ReadOnly Property Tierart() As String
Private Shared Function _
AtDebuggerDisplayFormatOutput(ByVal p As Object) As String
Private ReadOnly Property AtDebuggerDisplay() As String
Private $Anzahl As Integer
Private ReadOnly $Tierart As String
End Class
Aus dem Sichtbarkeitsmodifikator Friend können Sie schließen, dass anonyme Typen auf die Anwendung beschränkt sind, in der sie erzeugt werden.
Hinweis |
Klassennamen mit Sonderzeichen wie $ oder ` bleiben dem Compiler vorbehalten (genauer: dem übersetzten Code in der Intermediate Language). |
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.