Řazené kolekce členů (Visual Basic)
Od jazyka Visual Basic 2017 nabízí jazyk Visual Basic integrovanou podporu pro řazené kolekce členů, díky čemuž je vytváření řazených kolekcí členů a přístup k prvkům řazených kolekcí členů jednodušší. Řazená kolekce členů je jednoduchá datová struktura, která má určitý počet a posloupnost hodnot. Při vytváření instance řazené kolekce členů definujete číslo a datový typ každé hodnoty (nebo prvku). Například řazená kolekce řazených kolekcí členů (nebo dvojice) má dva prvky. První může být Boolean
hodnota, zatímco druhá je .String
Protože řazené kolekce členů usnadňují ukládání více hodnot do jednoho objektu, často se používají jako jednoduchý způsob, jak vrátit více hodnot z metody.
Důležité
Podpora řazené kolekce členů vyžaduje typ ValueTuple . Pokud rozhraní .NET Framework 4.7 není nainstalované, musíte přidat balíček System.ValueTuple
NuGet, který je k dispozici v galerii NuGet. Bez tohoto balíčku se může zobrazit chyba kompilace podobná tomu, že předdefinovaný typ ValueTuple(Of,,,) není definován nebo importován.
Vytvoření instance a použití řazené kolekce členů
Vytvoříte instanci řazené kolekce členů uzavřením hodnot oddělených čárkami do závorek. Každá z těchto hodnot se pak stane polem řazené kolekce členů. Následující kód například definuje trojitou kolekci členů (nebo tří členů) s Date
první hodnotou, String
jako druhou a Boolean
třetí.
Dim holiday = (#07/04/2017#, "Independence Day", True)
Ve výchozím nastavení se název každého pole v řazené kolekci členů skládá z řetězce Item
spolu s 1 umístěním pole v řazené kolekci členů. Pro tuto 3řazenou kolekci Date
členů je Item1
pole , String
pole je Item2
a Boolean
pole je Item3
. Následující příklad zobrazí hodnoty polí řazené kolekce členů v předchozím řádku kódu.
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
Pole řazené kolekce členů jazyka Visual Basic jsou read-write; Po vytvoření instance řazené kolekce členů můžete upravit její hodnoty. Následující příklad upraví dvě ze tří polí řazené kolekce členů vytvořené v předchozím příkladu a zobrazí výsledek.
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
Vytvoření instance a použití pojmenované řazené kolekce členů
Místo použití výchozích názvů polí řazené kolekce členů můžete vytvořit instanci pojmenované řazené kolekce členů přiřazením vlastních názvů k prvkům řazené kolekce členů. Pole řazené kolekce členů pak můžou být přístupná jejich přiřazenými jmény nebo jejich výchozími názvy. Následující příklad vytvoří instanci stejné 3řazené kolekce členů jako dříve, s tím rozdílem, že explicitně pojmenuje první pole EventDate
, druhé Name
a třetí IsHoliday
. Potom zobrazí hodnoty polí, upraví je a znovu zobrazí hodnoty polí.
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
Názvy řazených kolekcí členů můžete také zadat jako součást deklarace typu proměnné, pole nebo parametru:
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
nebo ve návratovém typu metody.
To je užitečné zejména při poskytování řazených kolekcí kolekcí inicializátoru; Názvy řazené kolekce členů lze zadat jako součást deklarace typu kolekce:
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
Odvozené názvy elementů řazené kolekce členů
Počínaje jazykem Visual Basic 15.3 může Visual Basic odvodit názvy prvků řazené kolekce členů; nemusíte je explicitně přiřazovat. Odvozené názvy řazené kolekce členů jsou užitečné při inicializaci řazené kolekce členů ze sady proměnných a chcete, aby název elementu řazené kolekce členů byl stejný jako název proměnné.
Následující příklad vytvoří řazenou kolekci stateInfo
členů, která obsahuje tři explicitně pojmenované prvky, state
, stateName
a capital
. Všimněte si, že při pojmenování prvků inicializační příkaz řazené kolekce členů jednoduše přiřadí pojmenované prvky hodnoty identicky pojmenovaných proměnných.
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
Vzhledem k tomu, že prvky a proměnné mají stejný název, kompilátor jazyka Visual Basic může odvodit názvy polí, jak ukazuje následující příklad.
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
Chcete-li povolit odvozené názvy elementů řazené kolekce členů, je nutné definovat verzi kompilátoru jazyka Visual Basic, která se má použít v souboru projektu jazyka Visual Basic (*.vbproj):
<PropertyGroup>
<LangVersion>15.3</LangVersion>
</PropertyGroup>
Číslo verze může být libovolná verze kompilátoru jazyka Visual Basic počínaje verzí 15.3. Místo toho, abyste pevně zakódovali konkrétní verzi kompilátoru, můžete také zadat "Latest" jako hodnotu LangVersion
kompilace s nejnovější verzí kompilátoru jazyka Visual Basic nainstalované ve vašem systému.
Další informace najdete v tématu Nastavení jazykové verze jazyka Visual Basic.
V některých případech nemůže kompilátor jazyka Visual Basic odvodit název elementu řazené kolekce členů z kandidáta a pole řazené kolekce členů lze odkazovat pouze pomocí jeho výchozího názvu, například Item1
, Item2
atd. Patří mezi ně:
Jméno kandidáta je stejné jako název člena řazené kolekce členů, například
Item3
,Rest
neboToString
.Název kandidáta je duplikován v řazené kolekci členů.
Pokud odvození názvu pole selže, Visual Basic negeneruje chybu kompilátoru ani není vyvolán výjimka za běhu. Místo toho musí být pole řazené kolekce členů odkazována jejich předdefinovanými názvy, například Item1
a Item2
.
Řazené kolekce členů versus struktury
Řazená kolekce členů jazyka Visual Basic je typ hodnoty, který je instancí jednoho z obecných typů System.ValueTuple . Například holiday
řazená kolekce členů definovaná v předchozím příkladu ValueTuple<T1,T2,T3> je instancí struktury. Je navržená tak, aby byla jednoduchým kontejnerem pro data. Vzhledem k tomu, že řazená kolekce členů má usnadnit vytvoření objektu s více datovými položkami, chybí některé z funkcí, které by mohla mít vlastní struktura. Tady jsou některé z nich:
Vlastní členové. Pro řazenou kolekci členů nelze definovat vlastní vlastnosti, metody nebo události.
Validace. Data přiřazená k polím nelze ověřit.
Neproměnlivost. Řazené kolekce členů jazyka Visual Basic jsou proměnlivé. Naproti tomu vlastní struktura umožňuje řídit, zda je instance proměnlivá nebo neměnná.
Pokud jsou důležité vlastní členy, vlastnosti a ověřování polí nebo neměnnost, měli byste k definování vlastního typu hodnoty použít příkaz Visual Basic Structure .
Řazená kolekce členů jazyka Visual Basic dědí členy svého typu ValueTuple . Kromě polí zahrnují následující metody:
metoda | Popis |
---|---|
CompareTo | Porovná aktuální řazenou kolekci členů s jinou řazenou kolekcí členů se stejným počtem prvků. |
Je rovno | Určuje, zda aktuální řazená kolekce členů je rovna jiné řazené kolekci členů nebo objektu. |
GetHashCode | Vypočítá kód hash pro aktuální instanci. |
ToString | Vrátí řetězcovou reprezentaci této řazené kolekce členů, která má tvar (Item1, Item2...) , kde Item1 a Item2 představuje hodnoty polí řazené kolekce členů. |
Kromě toho typy ValueTuple implementují IStructuralComparable a IStructuralEquatable rozhraní, které umožňují definovat vlastní porovnávače.
Přiřazení a řazené kolekce členů
Visual Basic podporuje přiřazení mezi typy řazené kolekce členů, které mají stejný počet polí. Typy polí lze převést, pokud platí jedna z následujících možností:
Zdrojové a cílové pole mají stejný typ.
Je definován rozšiřující (nebo implicitní) převod zdrojového typu na cílový typ.
Option Strict
jeOn
definována zúžení (nebo explicitní) převod typu zdroje na cílový typ. Tento převod může vyvolat výjimku, pokud je zdrojová hodnota mimo rozsah cílového typu.
Jiné převody se pro přiřazení nepovažují. Podívejme se na typy přiřazení, která jsou mezi typy řazených kolekcí členů povolená.
Vezměte v úvahu tyto proměnné použité v následujících příkladech:
' 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")
První dvě proměnné unnamed
a anonymous
, nemají sémantické názvy zadané pro pole. Jejich názvy polí jsou výchozí Item1
a Item2
. Poslední dvě proměnné named
a differentName
mají sémantické názvy polí. Všimněte si, že tyto dvě řazené kolekce členů mají pro pole různé názvy.
Všechny čtyři z těchto řazených kolekcí členů mají stejný počet polí (označovaných jako "arity"), a typy těchto polí jsou stejné. Proto všechna tato přiřazení fungují:
' 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
Všimněte si, že názvy řazených kolekcí členů nejsou přiřazeny. Hodnoty polí jsou přiřazeny podle pořadí polí v řazené kolekci členů.
Nakonec si všimněte, že řazenou kolekci členů můžeme přiřadit named
řazené conversion
kolekci členů, i když první pole named
je pole Integer
a první pole conversion
je .Long
Toto přiřazení je úspěšné, protože převod na Integer
hodnotu je Long
rozšiřující převod.
' 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)
Řazené kolekce členů s různými čísly polí nelze přiřadit:
' 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
Řazené kolekce členů jako návratové hodnoty metody
Metoda může vrátit pouze jednu hodnotu. Často byste ale chtěli, aby volání metody vrátilo více hodnot. Toto omezení můžete obejít několika způsoby:
Můžete vytvořit vlastní třídu nebo strukturu, jejíž vlastnosti nebo pole představují hodnoty vrácené metodou. Jedná se o těžké řešení; vyžaduje, abyste definovali vlastní typ, jehož jediným účelem je načíst hodnoty z volání metody.
Můžete vrátit jednu hodnotu z metody a vrátit zbývající hodnoty jejich předáním odkazem na metodu. To zahrnuje režii vytvoření instance proměnné a rizik neúmyslně přepsání hodnoty proměnné, kterou předáte odkazem.
Můžete použít řazenou kolekci členů, která poskytuje jednoduché řešení pro načtení více vrácených hodnot.
Například metody TryParse v .NET vrátí Boolean
hodnotu, která označuje, zda byla operace analýzy úspěšná. Výsledek operace analýzy je vrácen v proměnné předané odkazem na metodu. Za normálních okolností volání metody analýzy, například Integer.TryParse , vypadá takto:
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
Pokud zabalíme volání metody Integer.TryParse v naší vlastní metodě, můžeme vrátit řazenou kolekci členů z operace analýzy. V následujícím příkladu NumericLibrary.ParseInteger
volá Integer.TryParse metoda a vrátí pojmenovanou řazenou kolekci členů se dvěma prvky.
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
Pak můžete metodu volat pomocí kódu, jako je následující:
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
Kolekce členů a řazené kolekce členů jazyka Visual Basic v rozhraní .NET Framework
Řazená kolekce členů jazyka Visual Basic je instance jednoho z obecných typů System.ValueTuple , které byly zavedeny v rozhraní .NET Framework 4.7. Rozhraní .NET Framework obsahuje také sadu obecných tříd System.Tuple . Tyto třídy se však liší od řazených kolekcí členů jazyka Visual Basic a obecných typů System.ValueTuple několika způsoby:
Prvky tříd řazené kolekce členů jsou vlastnosti s názvem
Item1
,Item2
a tak dále. V řazených kolekcích členů jazyka Visual Basic a typech ValueTuple jsou prvky řazené kolekce členů pole.Nelze přiřadit smysluplné názvy k prvkům instance řazené kolekce členů nebo instance ValueTuple . Visual Basic umožňuje přiřadit názvy, které komunikují význam polí.
Vlastnosti instance řazené kolekce členů jsou jen pro čtení; řazené kolekce členů jsou neměnné. V řazených kolekcích členů jazyka Visual Basic a typech ValueTuple jsou pole řazená kolekce členů pro čtení i zápis. Řazené kolekce členů jsou proměnlivé.
Obecné typy řazené kolekce členů jsou odkazové typy. Použití těchto typů řazené kolekce členů znamená přidělování objektů. Na horkých cestách to může mít měřitelný dopad na výkon vaší aplikace. Řazené kolekce členů jazyka Visual Basic a typy ValueTuple jsou typy hodnot.
Rozšiřující metody ve TupleExtensions třídě usnadňují převod mezi řazené kolekce členů jazyka Visual Basic a objekty řazené kolekce členů .NET. ToTuple metoda převede řazenou kolekci členů jazyka Visual Basic na objekt .NET Tuple a ToValueTuple metoda převede objekt řazené kolekce členů .NET na řazenou kolekci členů jazyka Visual Basic.
Následující příklad vytvoří řazenou kolekci členů, převede ji na objekt řazené kolekce členů .NET a převede ji zpět na řazenou kolekci členů jazyka Visual Basic. Příklad pak porovná tuto řazenou kolekci členů s původní kolekcí členů, aby se zajistilo, že jsou stejné.
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