Typy anonimowe (Visual Basic)

Język Visual Basic obsługuje typy anonimowe, które umożliwiają tworzenie obiektów bez konieczności pisania definicji klasy dla typu danych. Zamiast tego kompilator generuje klasę. Klasa nie ma nazwy użytecznej, dziedziczy bezpośrednio z Objectklasy i zawiera właściwości określone w deklarowaniu obiektu. Ponieważ nazwa typu danych nie jest określona, jest ona określana jako typ anonimowy.

Poniższy przykład deklaruje i tworzy zmienną product jako wystąpienie typu anonimowego, który ma dwie właściwości i NamePrice.

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

Wyrażenie zapytania używa typów anonimowych do łączenia kolumn danych wybranych przez zapytanie. Nie można zdefiniować typu wyniku z wyprzedzeniem, ponieważ nie można przewidzieć kolumn, które może wybrać określone zapytanie. Typy anonimowe umożliwiają pisanie zapytania, które wybiera dowolną liczbę kolumn w dowolnej kolejności. Kompilator tworzy typ danych zgodny z określonymi właściwościami i określoną kolejnością.

W poniższych przykładach products znajduje się lista obiektów produktów, z których każda ma wiele właściwości. Zmienna namePriceQuery przechowuje definicję zapytania, które po jego wykonaniu zwraca kolekcję wystąpień typu anonimowego, która ma dwie właściwości i NamePrice.

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

Zmienna nameQuantityQuery przechowuje definicję zapytania, które po jego wykonaniu zwraca kolekcję wystąpień typu anonimowego, która ma dwie właściwości i NameOnHand.

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

Aby uzyskać więcej informacji na temat kodu utworzonego przez kompilator dla typu anonimowego, zobacz Definicja typu anonimowego.

Uwaga

Nazwa typu anonimowego jest generowana przez kompilator i może się różnić od kompilacji do kompilacji. Kod nie powinien używać ani polegać na nazwie typu anonimowego, ponieważ nazwa może ulec zmianie, gdy projekt zostanie ponownie skompilowany.

Deklarowanie typu anonimowego

Deklaracja wystąpienia typu anonimowego używa listy inicjatora do określania właściwości typu. Właściwości można określić tylko podczas deklarowania typu anonimowego, a nie innych elementów klasy, takich jak metody lub zdarzenia. W poniższym przykładzie product1 jest wystąpieniem typu anonimowego, które ma dwie właściwości: Name i 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}

Jeśli wyznaczysz właściwości jako właściwości klucza, możesz ich użyć do porównania dwóch wystąpień typu anonimowego pod kątem równości. Nie można jednak zmienić wartości właściwości klucza. Aby uzyskać więcej informacji, zobacz sekcję Właściwości klucza w dalszej części tego tematu.

Zwróć uwagę, że deklarowanie wystąpienia typu anonimowego przypomina deklarowanie wystąpienia nazwanego typu za pomocą inicjatora obiektu:

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

Aby uzyskać więcej informacji na temat innych sposobów określania właściwości typu anonimowego, zobacz How to: Infer Property Names and Types in Anonymous Type Deklaracje.

Właściwości kluczowe

Właściwości klucza różnią się od właściwości innych niż kluczowe na kilka podstawowych sposobów:

  • Tylko wartości właściwości klucza są porównywane w celu określenia, czy dwa wystąpienia są równe.

  • Wartości właściwości klucza są tylko do odczytu i nie można ich zmienić.

  • Tylko wartości właściwości klucza są uwzględniane w algorytmie kodu skrótu generowanego przez kompilator dla typu anonimowego.

Równość

Wystąpienia typów anonimowych mogą być równe tylko wtedy, gdy są wystąpieniami tego samego typu anonimowego. Kompilator traktuje dwa wystąpienia tego samego typu, jeśli spełniają następujące warunki:

  • Są one deklarowane w tym samym zestawie.

  • Ich właściwości mają te same nazwy, te same wywnioskowane typy i są deklarowane w tej samej kolejności. Porównania nazw nie są uwzględniane wielkości liter.

  • Te same właściwości w każdym z nich są oznaczone jako właściwości klucza.

  • Co najmniej jedna właściwość w każdej deklaracji jest właściwością klucza.

Wystąpienie typów anonimowych, które nie ma żadnych kluczowych właściwości, jest równe tylko samemu sobie.

' 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))

Dwa wystąpienia tego samego typu anonimowego są równe, jeśli wartości ich kluczowych właściwości są równe. W poniższych przykładach pokazano, jak testowana jest równość.

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))

Wartości tylko do odczytu

Nie można zmienić wartości właściwości klucza. Na przykład w prod8 poprzednim przykładzie Name pola i Price to read-only, ale OnHand można je zmienić.

' 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

Typy anonimowe z wyrażeń zapytań

Wyrażenia zapytań nie zawsze wymagają tworzenia typów anonimowych. Jeśli to możliwe, używają istniejącego typu do przechowywania danych kolumny. Dzieje się tak, gdy zapytanie zwraca wszystkie rekordy ze źródła danych lub tylko jedno pole z każdego rekordu. W poniższych przykładach customers kodu jest kolekcją obiektów Customer klasy. Klasa ma wiele właściwości i można uwzględnić co najmniej jedną z nich w wyniku zapytania w dowolnej kolejności. W dwóch pierwszych przykładach nie są wymagane żadne typy anonimowe, ponieważ zapytania wybierają elementy nazwanych typów:

  • custs1 zawiera kolekcję ciągów, ponieważ cust.Name jest ciągiem.

    Dim custs1 = From cust In customers
                 Select cust.Name
    
  • custs2 zawiera kolekcję Customer obiektów, ponieważ każdy element customers obiektu jest obiektem Customer , a cały element jest wybierany przez zapytanie.

    Dim custs2 = From cust In customers
                 Select cust
    

Jednak odpowiednie typy nazwane nie zawsze są dostępne. Możesz wybrać nazwy klientów i adresy w jednym celu, numery identyfikatorów klientów i lokalizacje dla innego, a także nazwy klientów, adresy i historie zamówień dla jednej trzeciej. Typy anonimowe umożliwiają wybranie dowolnej kombinacji właściwości w dowolnej kolejności bez uprzedniego deklarowania nowego nazwanego typu do przechowywania wyniku. Zamiast tego kompilator tworzy typ anonimowy dla każdej kompilacji właściwości. Poniższe zapytanie wybiera tylko nazwę i numer identyfikacyjny klienta z każdego Customer obiektu w obiekcie customers. W związku z tym kompilator tworzy typ anonimowy zawierający tylko te dwie właściwości.

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

Nazwy i typy danych właściwości w typie anonimowym są pobierane z argumentów na Select, cust.Name i cust.ID. Właściwości w typie anonimowym tworzonym przez zapytanie są zawsze kluczowymi właściwościami. Po custs3 wykonaniu w poniższej For Each pętli wynik jest kolekcją wystąpień typu anonimowego z dwiema właściwościami Name klucza i ID.

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

Elementy w kolekcji reprezentowane przez custs3 są silnie typizowane, a funkcja IntelliSense umożliwia nawigowanie po dostępnych właściwościach i weryfikowanie ich typów.

Aby uzyskać więcej informacji, zobacz Wprowadzenie do LINQ w Visual Basic.

Podejmowanie decyzji o tym, czy używać typów anonimowych

Przed utworzeniem obiektu jako wystąpienia klasy anonimowej należy rozważyć, czy jest to najlepsza opcja. Jeśli na przykład chcesz utworzyć obiekt tymczasowy zawierający powiązane dane i nie potrzebujesz innych pól i metod, które mogą zawierać kompletna klasa, dobrym rozwiązaniem jest typ anonimowy. Typy anonimowe są również wygodne, jeśli chcesz wybrać różne właściwości dla każdej deklaracji lub jeśli chcesz zmienić kolejność właściwości. Jeśli jednak projekt zawiera kilka obiektów, które mają te same właściwości, w stałej kolejności można je łatwiej zadeklarować przy użyciu nazwanego typu z konstruktorem klasy. Na przykład przy użyciu odpowiedniego konstruktora łatwiej jest zadeklarować kilka wystąpień Product klasy niż zadeklarować kilka wystąpień typu anonimowego.

' 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}

Kolejną zaletą nazwanych typów jest to, że kompilator może przechwytywać przypadkowe pomylenie nazwy właściwości. W poprzednich przykładach , firstProd2secondProd2i thirdProd2 mają być wystąpieniami tego samego typu anonimowego. Jeśli jednak przypadkowo zadeklarowano thirdProd2 w jeden z następujących sposobów, jego typ różniłby się od typu firstProd2 i 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}

Co ważniejsze, istnieją ograniczenia dotyczące używania typów anonimowych, które nie mają zastosowania do wystąpień nazwanych typów. firstProd2, secondProd2i thirdProd2 są wystąpieniami tego samego typu anonimowego. Jednak nazwa udostępnionego typu anonimowego jest niedostępna i nie może być wyświetlana, gdy nazwa typu jest oczekiwana w kodzie. Na przykład nie można użyć typu anonimowego do zdefiniowania podpisu metody, zadeklarowania innej zmiennej lub pola ani w dowolnej deklaracji typu. W związku z tym typy anonimowe nie są odpowiednie, gdy trzeba udostępniać informacje między metodami.

Definicja typu anonimowego

W odpowiedzi na deklarację wystąpienia typu anonimowego kompilator tworzy nową definicję klasy zawierającą określone właściwości.

Jeśli typ anonimowy zawiera co najmniej jedną właściwość klucza, definicja zastępuje trzy elementy członkowskie dziedziczone z Object: Equals, GetHashCodei ToString. Kod utworzony na potrzeby testowania równości i określania wartości kodu skrótu uwzględnia tylko kluczowe właściwości. Jeśli typ anonimowy nie zawiera żadnych właściwości klucza, tylko ToString zostanie zastąpiony. Jawnie nazwane właściwości typu anonimowego nie mogą powodować konfliktu z tymi wygenerowanymi metodami. Oznacza to, że nie można nazwać właściwości za pomocą .Equalsmetody , .GetHashCodeani .ToString .

Definicje typów anonimowych, które mają co najmniej jedną właściwość klucza, również implementują System.IEquatable<T> interfejs, gdzie T jest typem typu anonimowego.

Aby uzyskać więcej informacji o kodzie utworzonym przez kompilator i funkcjonalność metod zastępowanych, zobacz Definicja typu anonimowego.

Zobacz też