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 Name
Price
.
' 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 Name
Price
.
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 Name
OnHand
.
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 elementcustomers
obiektu jest obiektemCustomer
, 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 , firstProd2
secondProd2
i 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
, secondProd2
i 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ą .Equals
metody , .GetHashCode
ani .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.