Анонимные типы (Visual Basic)

Visual Basic поддерживает анонимные типы, которые позволяют создавать объекты без написания определения класса для типа данных. Вместо этого компилятор создает класс для вас. Класс не имеет доступного имени, наследует непосредственно от Objectи содержит свойства, указанные при объявлении объекта. Так как имя типа данных не указано, он называется анонимным типом.

В следующем примере объявляется и создается переменная product в качестве экземпляра анонимного типа с двумя свойствами и NamePrice.

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

Выражение запроса использует анонимные типы для объединения столбцов данных, выбранных запросом. Невозможно заранее определить тип результата, так как вы не можете прогнозировать столбцы, которые может выбрать конкретный запрос. Анонимные типы позволяют создавать запрос, который выбирает любое количество столбцов в любом порядке. Компилятор создает тип данных, соответствующий указанным свойствам и указанному порядку.

В следующих примерах products представлен список объектов продукта, каждый из которых имеет множество свойств. Переменная namePriceQuery содержит определение запроса, который при выполнении возвращает коллекцию экземпляров анонимного типа с двумя свойствами и NamePrice.

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

Переменная nameQuantityQuery содержит определение запроса, который при выполнении возвращает коллекцию экземпляров анонимного типа с двумя свойствами и NameOnHand.

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

Дополнительные сведения о коде, созданном компилятором для анонимного типа, см. в разделе "Определение анонимного типа".

Внимание

Имя анонимного типа создается компилятором и может отличаться от компиляции до компиляции. Код не должен использовать или полагаться на имя анонимного типа, так как имя может измениться при повторной компиляции проекта.

Объявление анонимного типа

Объявление экземпляра анонимного типа использует список инициализатора для указания свойств типа. Можно указать только свойства при объявлении анонимного типа, а не других элементов класса, таких как методы или события. В следующем примере product1 — это экземпляр анонимного типа с двумя свойствами: Name и 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}

Если вы назначаете свойства в качестве ключевых свойств, их можно использовать для сравнения двух экземпляров анонимных типов для равенства. Однако значения ключевых свойств нельзя изменить. Дополнительные сведения см. в разделе "Свойства ключей" далее в этом разделе.

Обратите внимание, что объявление экземпляра анонимного типа похоже на объявление экземпляра именованного типа с помощью инициализатора объектов:

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

Дополнительные сведения о других способах указания свойств анонимного типа см. в разделе How to: Infer Property Name and Types in Anonymous Type Declarations.

Ключевые свойства

Ключевые свойства отличаются от неключевых свойств несколькими основными способами:

  • Сравниваются только значения ключевых свойств, чтобы определить, равны ли два экземпляра.

  • Значения ключевых свойств доступны только для чтения и не могут быть изменены.

  • Только значения ключевых свойств включаются в алгоритм хэш-кода компилятора для анонимного типа.

Equality

Экземпляры анонимных типов могут быть равными только в том случае, если они являются экземплярами одного и того же анонимного типа. Компилятор обрабатывает два экземпляра как экземпляры одного типа, если они соответствуют следующим условиям:

  • Они объявляются в той же сборке.

  • Их свойства имеют одинаковые имена, те же типы выводимых и объявляются в том же порядке. Сравнения имен не учитывает регистр.

  • Те же свойства в каждом отмечены как ключевые свойства.

  • По крайней мере одно свойство в каждом объявлении является ключевым свойством.

Экземпляр анонимных типов, не имеющий ключевых свойств, равен только самому себе.

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

Два экземпляра одного и того же анонимного типа равны, если значения их ключевых свойств равны. В следующих примерах показано, как проверяется равенство.

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

Значения только для чтения

Нельзя изменить значения ключевых свойств. Например, в prod8 предыдущем примере Name поля имеют значение, Price но OnHand могут быть измененыread-only.

' 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

Анонимные типы из выражений запросов

Выражения запросов не всегда требуют создания анонимных типов. По возможности они используют существующий тип для хранения данных столбца. Это происходит, когда запрос возвращает все записи из источника данных или только одно поле из каждой записи. В следующих примерах customers кода представляет собой коллекцию объектов Customer класса. Класс имеет множество свойств, и вы можете включить один или несколько из них в результат запроса в любом порядке. В первых двух примерах анонимные типы не требуются, так как запросы выбирают элементы именованных типов:

  • custs1 содержит коллекцию строк, так как cust.Name это строка.

    Dim custs1 = From cust In customers
                 Select cust.Name
    
  • custs2 содержит коллекцию Customer объектов, так как каждый элемент customers является Customer объектом, и весь элемент выбирается запросом.

    Dim custs2 = From cust In customers
                 Select cust
    

Однако подходящие именованные типы не всегда доступны. Вам может потребоваться выбрать имена клиентов и адреса для одной цели, номера идентификатора клиента и расположения для другого, а также имена клиентов, адреса и журналы заказов для третьего. Анонимные типы позволяют выбрать любое сочетание свойств в любом порядке, не объявляя новый именованный тип для хранения результата. Вместо этого компилятор создает анонимный тип для каждой компиляции свойств. Следующий запрос выбирает только имя и идентификатор клиента из каждого Customer объекта.customers Поэтому компилятор создает анонимный тип, содержащий только эти два свойства.

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

Имена и типы данных свойств в анонимном типе взяты из аргументов Selectв и cust.Namecust.ID. Свойства анонимного типа, созданного запросом, всегда являются ключевыми свойствами. При custs3 выполнении в следующем For Each цикле результатом является коллекция экземпляров анонимного типа с двумя ключевыми свойствами и NameID.

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

Элементы в коллекции, представленные custs3 строго типизированными, и вы можете использовать IntelliSense для перехода по доступным свойствам и проверки их типов.

Дополнительные сведения см. в статье Знакомство с LINQ в Visual Basic.

Определение того, следует ли использовать анонимные типы

Прежде чем создавать объект в качестве экземпляра анонимного класса, рассмотрите, является ли это лучшим вариантом. Например, если вы хотите создать временный объект для хранения связанных данных, и у вас нет необходимости в других полях и методах, которые может содержать полный класс, анонимный тип является хорошим решением. Анонимные типы также удобны, если требуется другой выбор свойств для каждого объявления или изменение порядка свойств. Однако если проект включает несколько объектов с одинаковыми свойствами в фиксированном порядке, их можно объявить проще с помощью именованного типа с конструктором классов. Например, с соответствующим конструктором проще объявить несколько экземпляров класса, чем объявить несколько экземпляров Product анонимного типа.

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

Еще одним преимуществом именованных типов является то, что компилятор может перехватывать случайное несоответствие имени свойства. В предыдущих примерах firstProd2, secondProd2и thirdProd2 предназначены для экземпляров одного и того же анонимного типа. Однако если бы вы случайно объявили thirdProd2 одним из следующих способов, его тип будет отличаться от firstProd2 типа и 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}

Более важно, существуют ограничения на использование анонимных типов, которые не применяются к экземплярам именованных типов. firstProd2, secondProd2и thirdProd2 являются экземплярами одного и того же анонимного типа. Однако имя общего анонимного типа недоступно и не может отображаться, где в коде ожидается имя типа. Например, анонимный тип нельзя использовать для определения сигнатуры метода, объявления другой переменной или поля или в любом объявлении типа. В результате анонимные типы не подходят, если необходимо совместно использовать информацию между методами.

Определение анонимного типа

В ответ на объявление экземпляра анонимного типа компилятор создает новое определение класса, содержащее указанные свойства.

Если анонимный тип содержит по крайней мере одно свойство ключа, определение переопределяет три члена, унаследованные от Object: Equals, GetHashCodeи ToString. Код, созданный для тестирования равенства, и определение хэш-значения кода учитывает только ключевые свойства. Если анонимный тип не содержит ключевых свойств, переопределяется только ToString . Явно именованные свойства анонимного типа не могут конфликтовировать с этими созданными методами. Т. е. нельзя использовать .Equals.GetHashCodeили .ToString именовать свойство.

Определения анонимного типа, имеющие по крайней мере одно свойство ключа, также реализуют System.IEquatable<T> интерфейс, где T является тип анонимного типа.

Дополнительные сведения о коде, созданном компилятором и функциональными возможностями переопределенных методов, см. в разделе "Определение анонимного типа".

См. также