Anonyme Typen (Visual Basic)

Visual Basic unterstützt anonyme Typen, mit denen Sie Objekte erstellen können, ohne eine Klassendefinition für den Datentyp zu schreiben. Stattdessen erzeugt der Compiler eine Klasse. Die Klasse hat keinen verwendbaren Namen, erbt direkt von Object und enthält die von Ihnen in der Deklaration des Objekts angegebenen Eigenschaften. Da der Name des Typs nicht angegeben ist, wird er als anonymer Typ bezeichnet.

Im folgenden Beispiel wird die Variable product als Instanz eines anonymen Typs mit zwei Eigenschaften, Name und Price, deklariert und erstellt.

' Variable product is an instance of a simple anonymous type.
Dim product = New With {Key .Name = "paperclips", .Price = 1.29}

Ein Abfrageausdruck verwendet anonyme Typen, um Spalten mit Daten zu kombinieren, die von einer Abfrage ausgewählt wurden. Sie können den Typ des Ergebnisses nicht im Voraus definieren, da Sie die Spalten, die eine bestimmte Abfrage auswählen könnte, nicht vorhersagen können. Mit anonymen Typen können Sie eine Abfrage schreiben, die eine beliebige Anzahl von Spalten in beliebiger Reihenfolge auswählt. Der Compiler erstellt einen Datentyp, der den angegebenen Eigenschaften und der angegebenen Reihenfolge entspricht.

In den folgenden Beispielen ist products eine Liste von Produktobjekten, von denen jedes über viele Eigenschaften verfügt. Die Variable namePriceQuery enthält die Definition einer Abfrage, die bei der Ausführung eine Auflistung von Instanzen eines anonymen Typs mit zwei Eigenschaften, Name und Price, zurückgibt.

Dim namePriceQuery = From prod In products
                     Select prod.Name, prod.Price

Die Variable nameQuantityQuery enthält die Definition einer Abfrage, die bei der Ausführung eine Auflistung von Instanzen eines anonymen Typs mit zwei Eigenschaften, Name und OnHand, zurückgibt.

Dim nameQuantityQuery = From prod In products
                        Select prod.Name, prod.OnHand

Weitere Informationen zu dem vom Compiler für einen anonymen Typ erstellten Code finden Sie unter Definition des anonymen Typs.

Achtung

Der Name des anonymen Typs wird vom Compiler generiert und kann von Kompilierung zu Kompilierung variieren. Ihr Code sollte den Namen eines anonymen Typs nicht verwenden oder davon abhängig sein, da sich der Name möglicherweise ändert, wenn ein Projekt neu kompiliert wird.

Deklarieren eines anonymen Typs

Die Deklaration einer Instanz eines anonymen Typs verwendet eine Initialisiererliste, um die Eigenschaften des Typs anzugeben. Sie können nur Eigenschaften angeben, wenn Sie einen anonymen Typ deklarieren, nicht andere Klassenelemente wie Methoden oder Ereignisse. Im folgenden Beispiel ist product1 eine Instanz eines anonymen Typs mit zwei Eigenschaften: Name und Price.

' Variable product1 is an instance of a simple anonymous type.
Dim product1 = New With {.Name = "paperclips", .Price = 1.29}
' -or-
' product2 is an instance of an anonymous type with key properties.
Dim product2 = New With {Key .Name = "paperclips", Key .Price = 1.29}

Wenn Sie Eigenschaften als Schlüsseleigenschaften festlegen, können Sie sie verwenden, um zwei anonyme Typinstanzen auf Gleichheit zu vergleichen. Die Werte der Schlüsseleigenschaften können jedoch nicht geändert werden. Weitere Informationen finden Sie im Abschnitt Schlüsseleigenschaften weiter unten in diesem Thema.

Beachten Sie, dass das Deklarieren einer Instanz eines anonymen Typs wie das Deklarieren einer Instanz eines benannten Typs mit einem Objektinitialisierer ist:

' Variable product3 is an instance of a class named Product.
Dim product3 = New Product With {.Name = "paperclips", .Price = 1.29}

Weitere Informationen zu anderen Arten der Definition von Eigenschaften in anonymen Typen finden Sie unter Gewusst wie: Ableiten von Eigenschaftsnamen und -typen in anonymen Typdeklarationen.

Schlüsseleigenschaften

Schlüsseleigenschaften unterscheiden sich von nicht schlüsselbasierten Eigenschaften auf verschiedene grundlegende Weise:

  • Nur die Werte der Schlüsseleigenschaften werden verglichen, um zu bestimmen, ob zwei Instanzen gleich sind.

  • Die Werte der Schlüsseleigenschaften sind schreibgeschützt und können nicht geändert werden.

  • Nur Schlüsseleigenschaftenwerte sind im vom Compiler generierten Hashcodealgorithmus für einen anonymen Typ enthalten.

Gleichheit

Instanzen anonymer Typen können nur gleich sein, wenn es sich um Instanzen desselben anonymen Typs handelt. Der Compiler behandelt zwei Instanzen als Instanzen desselben Typs, wenn sie die folgenden Bedingungen erfüllen:

  • Sie werden in derselben Assembly deklariert.

  • Ihre Eigenschaften haben die gleichen Namen, die gleichen abgeleiteten Typen und werden in der gleichen Reihenfolge deklariert. Bei Namensvergleichen wird die Groß-/Kleinschreibung nicht beachtet.

  • Die gleichen Eigenschaften sind jeweils als Schlüsseleigenschaften gekennzeichnet.

  • Mindestens eine Eigenschaft in jeder Deklaration ist eine Schlüsseleigenschaft.

Eine Instanz eines anonymen Typs ohne Schlüsseleigenschaften ist nur mit sich selbst identisch.

' prod1 and prod2 have no key values.
Dim prod1 = New With {.Name = "paperclips", .Price = 1.29}
Dim prod2 = New With {.Name = "paperclips", .Price = 1.29}

' The following line displays False, because prod1 and prod2 have no
' key properties.
Console.WriteLine(prod1.Equals(prod2))

' The following statement displays True because prod1 is equal to itself.
Console.WriteLine(prod1.Equals(prod1))

Zwei Instanzen desselben anonymen Typs sind gleich, wenn die Werte ihrer Schlüsseleigenschaften gleich sind. Die folgenden Beispiele veranschaulichen, wie Gleichheit getestet wird.

Dim prod3 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod4 = New With {Key .Name = "paperclips", Key .Price = 1.29}
' The following line displays True, because prod3 and prod4 are
' instances of the same anonymous type, and the values of their
' key properties are equal.
Console.WriteLine(prod3.Equals(prod4))

Dim prod5 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim prod6 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays False, because prod5 and prod6 do not 
' have the same properties.
Console.WriteLine(prod5.Equals(prod6))

Dim prod7 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 24}
Dim prod8 = New With {Key .Name = "paperclips", Key .Price = 1.29,
                      .OnHand = 423}
' The following line displays True, because prod7 and prod8 are
' instances of the same anonymous type, and the values of their
' key properties are equal. The equality check does not compare the
' values of the non-key field.
Console.WriteLine(prod7.Equals(prod8))

Read-Only Werte

Die Werte der Schlüsseleigenschaften können nicht geändert werden. In prod8 im vorherigen Beispiel sind die Felder Name und Priceread-only, aber OnHand kann geändert werden.

' The following statement will not compile, because Name is a key
' property and its value cannot be changed.
' prod8.Name = "clamps"

' OnHand is not a Key property. Its value can be changed.
prod8.OnHand = 22

Anonyme Typen aus Abfrageausdrücken

Abfrageausdrücke erfordern nicht immer die Erstellung anonymer Typen. Wenn möglich, verwenden sie einen vorhandenen Typ, um die Spaltendaten zu enthalten. Dies tritt auf, wenn die Abfrage entweder ganze Datensätze aus der Datenquelle oder nur ein Feld aus jedem Datensatz zurückgibt. In den folgenden Codebeispielen ist customers eine Auflistung von Objekten einer Customer-Klasse. Die Klasse verfügt über viele Eigenschaften, und Sie können eine oder mehrere davon in beliebiger Reihenfolge in das Abfrageergebnis einschließen. In den ersten beiden Beispielen sind keine anonymen Typen erforderlich, da die Abfragen Elemente benannter Typen auswählen:

  • custs1 enthält eine Auflistung von Zeichenfolgen, da es sich bei cust.Name um eine Zeichenfolge handelt.

    Dim custs1 = From cust In customers
                 Select cust.Name
    
  • custs2 enthält eine Auflistung von Customer-Objekten, da jedes Element von customers ein Customer-Objekt ist und das gesamte Element von der Abfrage ausgewählt wird.

    Dim custs2 = From cust In customers
                 Select cust
    

Geeignete benannte Typen sind jedoch nicht immer verfügbar. Sie können Kundennamen und Adressen für einen Zweck, Kunden-ID-Nummern und Standorte für einen anderen und Kundennamen, Adressen und Bestellverläufe für einen dritten Zweck auswählen. Mit anonymen Typen können Sie eine beliebige Kombination von Eigenschaften in beliebiger Reihenfolge auswählen, ohne zuerst einen neuen benannten Typ zu deklarieren, der das Ergebnis enthält. Stattdessen erstellt der Compiler einen anonymen Typ für jede Kompilierung von Eigenschaften. Die folgende Abfrage wählt nur den Namen und die ID-Nummer des Kunden aus jedem Customer-Objekt in customers aus. Daher erstellt der Compiler einen anonymen Typ, der nur diese beiden Eigenschaften enthält.

Dim custs3 = From cust In customers
             Select cust.Name, cust.ID

Sowohl die Namen als auch die Datentypen der Eigenschaften im anonymen Typ werden von den Argumenten zu Select, cust.Name und cust.ID übernommen. Die Eigenschaften eines anonymen Typs, der von einer Abfrage erstellt wird, sind immer Schlüsseleigenschaften. Wenn custs3 in der folgenden For Each-Schleife ausgeführt wird, ist das Ergebnis eine Auflistung von Instanzen eines anonymen Typs mit zwei Schlüsseleigenschaften, Name und ID.

For Each selectedCust In custs3
    Console.WriteLine(selectedCust.ID & ": " & selectedCust.Name)
Next

Die Elemente in der Auflistung, die durch custs3 dargestellt werden, sind stark typisiert, und Sie können IntelliSense verwenden, um durch die verfügbaren Eigenschaften zu navigieren und deren Typen zu überprüfen.

Weitere Informationen finden Sie unter Einführung in LINQ in Visual Basic.

Entscheidung, ob anonyme Typen verwendet werden sollen

Bevor Sie ein Objekt als Instanz einer anonymen Klasse erstellen, überlegen Sie, ob dies die beste Option ist. Wenn Sie beispielsweise ein temporäres Objekt erstellen möchten, das verwandte Daten enthält, und Sie keine anderen Felder und Methoden benötigen, die eine vollständige Klasse enthalten könnte, ist ein anonymer Typ eine gute Lösung. Anonyme Typen sind auch geeignet, wenn Sie eine andere Auswahl von Eigenschaften für jede Deklaration wünschen oder wenn Sie die Reihenfolge der Eigenschaften ändern möchten. Wenn Ihr Projekt jedoch mehrere Objekte mit den gleichen Eigenschaften enthält, können Sie sie in einer festen Reihenfolge einfacher deklarieren, indem Sie einen benannten Typ mit einem Klassenkonstruktor verwenden. Mit einem entsprechenden Konstruktor ist es beispielsweise einfacher, mehrere Instanzen einer Product-Klasse zu deklarieren, als mehrere Instanzen eines anonymen Typs zu deklarieren.

' Declaring instances of a named type.
Dim firstProd1 As New Product("paperclips", 1.29)
Dim secondProd1 As New Product("desklamp", 28.99)
Dim thirdProd1 As New Product("stapler", 5.09)

' Declaring instances of an anonymous type.
Dim firstProd2 = New With {Key .Name = "paperclips", Key .Price = 1.29}
Dim secondProd2 = New With {Key .Name = "desklamp", Key .Price = 28.99}
Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}

Ein weiterer Vorteil von benannten Typen ist, dass der Compiler eine versehentliche Fehltypisierung eines Eigenschaftsnamens abfangen kann. In den vorherigen Beispielen sind firstProd2, secondProd2 und thirdProd2 als Instanzen desselben anonymen Typs vorgesehen. Wenn Sie thirdProd2 jedoch versehentlich auf eine der folgenden Arten deklarieren würden, unterscheidet sich sein Typ von dem von firstProd2 und secondProd2.

' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = 5.09}
' Dim thirdProd2 = New With {Key .Name = "stapler", Key .Price = "5.09"}
' Dim thirdProd2 = New With {Key .Name = "stapler", .Price = 5.09}

Noch wichtiger ist, dass es Einschränkungen für die Verwendung anonymer Typen gibt, die nicht für Instanzen benannter Typen gelten. firstProd2, secondProd2und thirdProd2 sind Instanzen desselben anonymen Typs. Der Name für den freigegebenen anonymen Typ ist jedoch nicht verfügbar und kann nicht angezeigt werden, wenn in Ihrem Code ein Typname erwartet wird. Beispielsweise kann ein anonymer Typ nicht zum Definieren einer Methodensignatur, zum Deklarieren einer anderen Variablen oder eines anderen Felds oder in einer Typdeklaration verwendet werden. Daher sind anonyme Typen nicht geeignet, wenn Sie Informationen methodenübergreifend freigeben möchten.

Definition von anonymen Typen

Als Reaktion auf die Deklaration einer Instanz eines anonymen Typs erstellt der Compiler eine neue Klassendefinition, die die angegebenen Eigenschaften enthält.

Wenn ein anonymer Typ mindestens eine Schlüsseleigenschaft enthält, überschreibt die Definition drei Member, die von Object geerbt werden: Equals, GetHashCodeund ToString. Der Code, der zum Testen der Gleichheit und Bestimmung des Hashcodewerts erstellt wird, berücksichtigt nur die Schlüsseleigenschaften. Wenn der anonyme Typ keine Schlüsseleigenschaften enthält, wird nur ToString überschrieben. Explizit benannte Eigenschaften eines anonymen Typs können nicht mit diesen generierten Methoden in Konflikt geraten. Das heißt, Sie können .Equals, .GetHashCode und .ToString nicht verwenden, um eine Eigenschaft zu benennen.

Anonyme Typdefinitionen, die mindestens eine Schlüsseleigenschaft haben, implementieren auch die System.IEquatable<T>-Schnittstelle, wobei T der Typ des anonymen Typs ist.

Weitere Informationen zum vom Compiler erstellten Code und zur Funktionalität der überschriebenen Methoden finden Sie unter Definition des anonymen Typs.

Siehe auch