Кортежи (Visual Basic)
Начиная с Visual Basic 2017 язык Visual Basic предлагает встроенную поддержку кортежей, что упрощает создание кортежей и доступ к элементам кортежей. Кортеж — это упрощенная структура данных, которая имеет определенное число и последовательность значений. При создании экземпляра кортежа определяется число и тип данных каждого значения (или элемента). Например, 2-кортеж (или пара) содержит два элемента. Первое может быть значением Boolean
, а второй — String
значением. Так как кортежи упрощают хранение нескольких значений в одном объекте, они часто используются в качестве упрощенного способа возврата нескольких значений из метода.
Внимание
Для поддержки кортежей требуется ValueTuple тип. Если платформа .NET Framework 4.7 не установлен, необходимо добавить пакет System.ValueTuple
NuGet, который доступен в коллекции NuGet. Без этого пакета может возникнуть ошибка компиляции, аналогичная описанию "Предопределенный тип ValueTuple(Of,,,)" не определен или импортирован".
Создание экземпляров и использование кортежа
Создайте экземпляр кортежа, заключив значения с разделителями-запятыми в скобки. Затем каждое из этих значений становится полем кортежа. Например, следующий код определяет тройной (или 3 кортеж) с Date
его первым значением, String
а второй — Boolean
третьим.
Dim holiday = (#07/04/2017#, "Independence Day", True)
По умолчанию имя каждого поля в кортеже состоит из строки Item
вместе с одной позицией поля в кортеже. Для этого 3 кортежа Date
поле имеет Item1
значение , String
поле равноItem2
, а Boolean
поле — .Item3
В следующем примере отображаются значения полей кортежа, созданных в предыдущей строке кода.
Console.WriteLine($"{holiday.Item1} is {holiday.Item2}" +
$"{If(holiday.Item3, ", a national holiday", String.Empty)}")
' Output: 7/4/2017 12:00:00 AM Is Independence Day, a national holiday
Поля кортежа Visual Basic доступны для чтения и записи; После создания экземпляра кортежа можно изменить его значения. Следующий пример изменяет два из трех полей кортежа, созданного в предыдущем примере, и отображает результат.
holiday.Item1 = #01/01/2018#
holiday.Item2 = "New Year's Day"
Console.WriteLine($"{holiday.Item1} is {holiday.Item2}" +
$"{If(holiday.Item3, ", a national holiday", String.Empty)}")
' Output: 1/1/2018 12:00:00 AM Is New Year's Day, a national holiday
Создание экземпляров и использование именованного кортежа
Вместо использования имен по умолчанию для полей кортежа можно создать экземпляр именованного кортежа , назначив собственные имена элементам кортежа. Затем поля кортежа можно получить по назначенным именам или по умолчанию. В следующем примере создается экземпляр того же 3 кортежа, что и ранее, за исключением того, что он явно присваивает имя первому полю EventDate
, Name
второму и третьему IsHoliday
. Затем он отображает значения полей, изменяет их и снова отображает значения полей.
Dim holiday = (EventDate:=#07/04/2017#, Name:="Independence Day", IsHoliday:=True)
Console.WriteLine($"{holiday.EventDate} Is {holiday.Name}" +
$"{If(holiday.IsHoliday, ", a national holiday", String.Empty)}")
holiday.Item1 = #01/01/2018#
holiday.Item2 = "New Year's Day"
Console.WriteLine($"{holiday.Item1} is {holiday.Item2}" +
$"{If(holiday.Item3, ", a national holiday", String.Empty)}")
' The example displays the following output:
' 7/4/2017 12:00:00 AM Is Independence Day, a national holiday
' 1/1/2018 12:00:00 AM Is New Year's Day, a national holiday
Вы также можете указать имена кортежей в рамках объявления типа переменной, поля или параметра:
Dim holiday As (EventDate As Date, Name As String, IsHoliday As Boolean) =
(#07/04/2017#, "Independence Day", True)
Console.WriteLine(holiday.Name)
' Output: Independence Day
или в возвращаемом типе метода.
Это особенно полезно при предоставлении кортежей инициализатору коллекции; Имена кортежей можно указать в рамках объявления типа коллекции:
Dim events As New List(Of (EventDate As Date, Name As String, IsHoliday As Boolean)) From {
(#07/04/2017#, "Independence Day", True),
(#04/22/2017#, "Earth Day", False)
}
Console.WriteLine(events(1).IsHoliday)
' Output: False
Выводимые имена элементов кортежа
Начиная с Visual Basic 15.3, Visual Basic может выводить имена элементов кортежей; Их не нужно назначать явным образом. Выводимые имена кортежей полезны при инициализации кортежа из набора переменных, а имя элемента кортежа совпадает с именем переменной.
В следующем примере создается stateInfo
кортеж, содержащий три явно именованных элемента, state
stateName
и capital
. Обратите внимание, что при именовании элементов оператор инициализации кортежа просто назначает именованные элементы значения идентичных именованных переменных.
Const state As String = "MI"
Const stateName As String = "Michigan"
Const capital As String = "Lansing"
Dim stateInfo = (state:=state, stateName:=stateName, capital:=capital)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.state}, Capital {stateInfo.capital}")
' The example displays the following output:
' Michigan: 2-letter code: MI, Capital Lansing
Так как элементы и переменные имеют то же имя, компилятор Visual Basic может выводить имена полей, как показано в следующем примере.
Const state As String = "MI"
Const stateName As String = "Michigan"
Const capital As String = "Lansing"
Dim stateInfo = (state, stateName, capital)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.State}, Capital {stateInfo.capital}")
' The example displays the following output:
' Michigan: 2-letter code: MI, Capital Lansing
Чтобы включить выводимые имена элементов кортежа, необходимо определить версию компилятора Visual Basic для использования в файле проекта Visual Basic (*.vbproj):
<PropertyGroup>
<LangVersion>15.3</LangVersion>
</PropertyGroup>
Номер версии может быть любой версией компилятора Visual Basic, начиная с версии 15.3. Вместо жесткого написания определенной версии компилятора можно также указать "Последняя" в качестве значения LangVersion
для компиляции с последней версией компилятора Visual Basic, установленной в вашей системе.
Дополнительные сведения см. в разделе "Настройка версии языка Visual Basic".
В некоторых случаях компилятор Visual Basic не может выводить имя элемента кортежа из имени кандидата, а поле кортежа можно ссылаться только с помощью его имени по умолчанию, например Item1
, Item2
и т. д. К ним относятся:
Имя кандидата совпадает с именем элемента кортежа, например
Item3
,Rest
илиToString
.Имя кандидата дублируется в кортеже.
Если вывод имени поля завершается ошибкой, Visual Basic не создает ошибку компилятора и не вызывает исключение во время выполнения. Вместо этого поля кортежа должны ссылаться на их предопределенные имена, например Item1
и Item2
.
Кортежи и структуры
Кортеж Visual Basic — это тип значения, который является экземпляром одного из универсальных типов System.ValueTuple . Например, кортеж, определенный в предыдущем примере, holiday
является экземпляром ValueTuple<T1,T2,T3> структуры. Он предназначен для создания упрощенного контейнера для данных. Так как кортеж предназначен для упрощения создания объекта с несколькими элементами данных, он не имеет некоторых функций, которые может иметь пользовательская структура. Например:
Пользовательские члены. Нельзя определить собственные свойства, методы или события кортежа.
Проверка. Невозможно проверить данные, назначенные полям.
Неизменяемость. Кортежи Visual Basic изменяются. В отличие от этого, пользовательская структура позволяет контролировать, является ли экземпляр изменяемым или неизменяемым.
Если важны пользовательские элементы, свойство и проверка полей или неизменяемость, следует использовать инструкцию Структуры Visual Basic для определения пользовательского типа значения.
Кортеж Visual Basic наследует элементы своего типа ValueTuple . Помимо полей, к ним относятся следующие методы:
Метод | Description |
---|---|
CompareTo | Сравнивает текущий кортеж с другим кортежем с тем же количеством элементов. |
Равно | Определяет, равен ли текущий кортеж другому кортежу или объекту. |
GetHashCode | Вычисляет хэш-код для текущего экземпляра . |
ToString | Возвращает строковое представление этого кортежа, которое принимает форму (Item1, Item2...) , где Item1 и Item2 представляет значения полей кортежа. |
Кроме того, типы ValueTuple реализуют IStructuralComparable и IStructuralEquatable интерфейсы, которые позволяют определять пользовательские сравнения.
Назначение и кортежи
Visual Basic поддерживает назначение между типами кортежей с одинаковым количеством полей. Типы полей можно преобразовать, если одно из следующих значений имеет значение true:
Исходное и целевое поле имеют одинаковый тип.
Определяется расширение (или неявное) преобразование исходного типа в целевой тип.
Option Strict
—On
это , а сужающее (или явное) преобразование исходного типа в целевой тип определяется. Это преобразование может вызвать исключение, если исходное значение находится за пределами диапазона целевого типа.
Другие преобразования в контексте назначений не учитываются. Рассмотрим возможные виды назначений между типами кортежей.
В приведенных ниже примерах можно использовать указанные переменные:
' The number and field types of all these tuples are compatible.
' The only difference Is the field names being used.
Dim unnamed = (42, "The meaning of life")
Dim anonymous = (16, "a perfect square")
Dim named = (Answer:=42, Message:="The meaning of life")
Dim differentNamed = (SecretConstant:=42, Label:="The meaning of life")
Первые две переменные unnamed
и anonymous
не имеют семантических имен, предоставленных для полей. Их имена полей являются именами по умолчанию Item1
и Item2
. Последние две переменные named
и differentName
имена семантических полей. Обратите внимание на то, что поля в этих двух кортежах называются по-разному.
Все четыре из этих кортежей имеют одинаковое количество полей (например, arity), а типы этих полей идентичны. Таким образом, все эти назначения работают:
' Assign named to unnamed.
named = unnamed
' Despite the assignment, named still has fields that can be referred to as 'answer' and 'message'.
Console.WriteLine($"{named.Answer}, {named.Message}")
' Output: 42, The meaning of life
' Assign unnamed to anonymous.
anonymous = unnamed
' Because of the assignment, the value of the elements of anonymous changed.
Console.WriteLine($"{anonymous.Item1}, {anonymous.Item2}")
' Output: 42, The meaning of life
' Assign one named tuple to the other.
named = differentNamed
' The field names are Not assigned. 'named' still has 'answer' and 'message' fields.
Console.WriteLine($"{named.Answer}, {named.Message}")
' Output: 42, The meaning of life
Обратите внимание на то, что имена кортежей не назначаются. Значения полей назначаются в соответствии с порядком полей в кортеже.
Наконец, обратите внимание, что мы можем назначить named
кортеж conversion
кортеже, даже если первое поле является и Integer
первым полем named
conversion
является .Long
Это назначение завершается успешно, так как преобразование Integer
в объект Long
является расширением.
' Assign an (Integer, String) tuple to a (Long, String) tuple (using implicit conversion).
Dim conversion As (Long, String) = named
Console.WriteLine($"{conversion.Item1} ({conversion.Item1.GetType().Name}), " +
$"{conversion.Item2} ({conversion.Item2.GetType().Name})")
' Output: 42 (Int64), The meaning of life (String)
Кортежи с разными числами полей не могут назначаться:
' Does not compile.
' VB30311: Value of type '(Integer, Integer, Integer)' cannot be converted
' to '(Answer As Integer, Message As String)'
var differentShape = (1, 2, 3)
named = differentShape
Кортежи как возвращаемые значения методов
Метод может возвращать только одно значение. Однако часто требуется вызов метода для возврата нескольких значений. Существует несколько способов обойти это ограничение:
Можно создать пользовательский класс или структуру, свойства или поля которых представляют значения, возвращаемые методом. Это решение в тяжелом весе; Для этого необходимо определить пользовательский тип, цель которого — получить значения из вызова метода.
Можно вернуть одно значение из метода и вернуть оставшиеся значения, передав их по ссылке на метод. Это включает в себя затраты на создание экземпляра переменной и рисков, которые непреднамеренно перезаписывают значение переменной, передаваемой по ссылке.
Кортеж можно использовать, предоставляющий упрощенное решение для получения нескольких возвращаемых значений.
Например, методы TryParse в .NET возвращают Boolean
значение, указывающее, выполнена ли операция синтаксического анализа. Результат операции синтаксического анализа возвращается в переменной, передаваемой ссылкой на метод. Обычно вызов метода синтаксического анализа, например Integer.TryParse , выглядит следующим образом:
Dim numericString As String = "123456"
Dim number As Integer
Dim result = Integer.TryParse(numericString, number)
Console.WriteLine($"{If(result, $"Success: {number:N0}", "Failure")}")
' Output: Success: 123,456
Мы можем вернуть кортеж из операции синтаксического анализа, если мы заключим вызов метода Integer.TryParse в нашем собственном методе. В следующем примере NumericLibrary.ParseInteger
вызывает метод Integer.TryParse и возвращает именованный кортеж с двумя элементами.
Imports System.Globalization
Public Module NumericLibrary
Public Function ParseInteger(value As String) As (Success As Boolean, Number As Integer)
Dim number As Integer
Return (Integer.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, number), number)
End Function
End Module
Затем можно вызвать метод с кодом, как показано ниже:
Dim numericString As String = "123,456"
Dim result = ParseInteger(numericString)
Console.WriteLine($"{If(result.Success, $"Success: {result.Number:N0}", "Failure")}")
Console.ReadLine()
' Output: Success: 123,456
Кортежи и кортежи Visual Basic в платформа .NET Framework
Кортеж Visual Basic — это экземпляр одного из универсальных типов System.ValueTuple, которые были представлены в платформа .NET Framework 4.7. Платформа .NET Framework также включает набор универсальных классов System.Tuple. Однако эти классы отличаются от кортежей Visual Basic и универсальных типов System.ValueTuple несколькими способами:
Элементы классов кортежей — это свойства с именем
Item1
,Item2
и т. д. В кортежах Visual Basic и типах ValueTuple элементы кортежа являются полями.Не удается назначить значимые имена элементам экземпляра кортежа или экземпляра ValueTuple . Visual Basic позволяет назначать имена, которые передают значение полей.
Свойства экземпляра Кортежа доступны только для чтения. Кортежи неизменяемы. В кортежах Visual Basic и типах ValueTuple поля кортежей считываются и записываются; кортежи являются изменяемыми.
Универсальные типы кортежей являются ссылочными типами. Использование этих типов кортежей означает выделение объектов. В критических путях это может заметно влиять на производительность приложения. Кортежи Visual Basic и типы ValueTuple — это типы значений.
Методы расширения в TupleExtensions классе упрощают преобразование между кортежами Visual Basic и объектами кортежей .NET. Метод ToTuple преобразует кортеж Visual Basic в объект Кортежа .NET, а метод ToValueTuple преобразует объект кортежа .NET в кортеж Visual Basic.
В следующем примере создается кортеж, он преобразуется в объект кортежа .NET и преобразует его обратно в кортеж Visual Basic. Затем пример сравнивает этот кортеж с исходным, чтобы убедиться, что они равны.
Dim cityInfo = (name:="New York", area:=468.5, population:=8_550_405)
Console.WriteLine($"{cityInfo}, type {cityInfo.GetType().Name}")
' Convert the Visual Basic tuple to a .NET tuple.
Dim cityInfoT = TupleExtensions.ToTuple(cityInfo)
Console.WriteLine($"{cityInfoT}, type {cityInfoT.GetType().Name}")
' Convert the .NET tuple back to a Visual Basic tuple and ensure they are the same.
Dim cityInfo2 = TupleExtensions.ToValueTuple(cityInfoT)
Console.WriteLine($"{cityInfo2}, type {cityInfo2.GetType().Name}")
Console.WriteLine($"{NameOf(cityInfo)} = {NameOf(cityInfo2)}: {cityInfo.Equals(cityInfo2)}")
' The example displays the following output:
' (New York, 468.5, 8550405), type ValueTuple`3
' (New York, 468.5, 8550405), type Tuple`3
' (New York, 468.5, 8550405), type ValueTuple`3
' cityInfo = cityInfo2 : True