Анонимные типы

Обновлен: Ноябрь 2007

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

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

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

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

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

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

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

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

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

Bb384767.alert_caution(ru-ru,VS.90).gifВнимание!

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

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

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

Более подробное сравнение объявлений именованных и анонимных типов содержится в разделе Сравнение именованных и анонимных типов.

Дополнительные сведения о других способах указания свойств анонимного типа содержатся в разделе Практическое руководство. Выведение имен свойств и типов в объявлениях анонимных типов.

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

Основные отличительные особенности ключевых свойств от неключевых:

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

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

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

Равенство

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

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

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

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

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

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

' 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 являются read-only, но OnHand может изменяться.

' 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.Name и cust.ID. Свойства в анонимном типе, который создается при запросе всегда являются ключевыми свойствами. При выполнении custs3 в следующем цикле For Each результатом является коллекция экземпляров анонимного типа с двумя ключевыми свойствами Name и ID.

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 .Nmae = "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 — тип анонимного типа.

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

См. также

Задачи

Практическое руководство. Объявление экземпляра анонимного типа

Практическое руководство. Выведение имен свойств и типов в объявлениях анонимных типов

Основные понятия

Инициализаторы объектов: именованные и анонимные типы

Вывод локального типа

Знакомство с LINQ в Visual Basic

Сравнение именованных и анонимных типов

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

Ссылки

Key (Visual Basic)