Sdílet prostřednictvím


Řazené kolekce členů (Visual Basic)

Od verze Visual Basic 2017 nabízí jazyk Visual Basic integrovanou podporu pro n-tice, díky čemuž je vytváření a přístup k prvkům n-tic 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 dvojice (2-kombinace) má dva prvky. První může být Boolean hodnota, zatímco druhá je String hodnota. 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 n-tice vyžaduje typ ValueTuple. Pokud rozhraní .NET Framework 4.7 není nainstalované, musíte přidat balíček System.ValueTupleNuGet, 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.

Instancování a použití n-tice

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 položkou n-tice. Následující kód například definuje trojici (nebo tříprvkovou n-tici) kde je Date první hodnota, String jako druhá 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 n-tici skládá z řetězce Item spolu s pozicí pole začínající jedničkou v n-tici. Pro tuto trojici je pole DateItem1, pole String je Item2, a pole Boolean je Item3. Následující příklad zobrazuje hodnoty polí n-tice vytvořené 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 n-tice v jazyce Visual Basic lze číst i zapisovat; po vytvoření instance n-tice můžete upravit její hodnoty. Následující příklad upraví dvě ze tří polí n-tice 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é n-tice

Místo použití výchozích názvů polí v n-tici můžete vytvořit instanci pojmenované n-tice přiřazením vlastních názvů prvkům n-tice. 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é trojice jako dříve, s tím rozdílem, že explicitně pojmenuje první pole jako EventDate, druhé jako Name, a třetí jako 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 n-tic 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í n-tic inicializátoru kolekce; názvy n-tic 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 n-tice jsou užitečné, když inicializujete n-tici z množiny proměnných a chcete, aby název prvku n-tice byl stejný jako název proměnné.

Následující příklad vytvoří n-tici stateInfo, 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"
Dim stateInfo = (state:=state, stateName:=stateName)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.state}")
' 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 prvku n-tice z kandidátního názvu a pole n-tice 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 n-tice, například Item3, Rest, nebo ToString.

  • Jméno kandidáta je duplikováno v n-tici.

Pokud odvození názvu pole selže, Visual Basic negeneruje chybu kompilátoru ani nevyvolá žádnou výjimku za běhu. Místo toho musí být pole n-tic odkazována jejich předdefinovanými názvy, např. Item1 a Item2.

Řazené kolekce členů versus struktury

n-tice v jazyce Visual Basic je datový typ hodnoty, jímž je instance jednoho z System.ValueTuple obecných typů. Například holiday n-tice definovaná v předchozím příkladu je instancí struktury ValueTuple<T1,T2,T3>. 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. n-tice v jazyce Visual Basic jsou měnitelné. 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ě svých polí zahrnuje také následující metody:

metoda Popis
CompareTo Porovná aktuální n-tici s jinou n-ticí se stejným počtem prvků.
Je rovno Určuje, zda je aktuální n-tice rovna jiné n-tici nebo objektu.
GetHashCode Vypočítá kód hash pro aktuální instanci.
ToString (funkce pro převod objektu na textový řetězec) Vrátí řetězcovou reprezentaci této n-tice, která má tvar (Item1, Item2...), kde Item1 a Item2 představují hodnoty polí n-tice.

Kromě toho typy ValueTuple implementují IStructuralComparable a IStructuralEquatable rozhraní, které umožňují definovat vlastní porovnávače.

Přiřazení a n-tice

Visual Basic podporuje přiřazení mezi typy n-tic, které mají stejný počet položek. 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 je On, a je definována konverze typu zdroje na cílový typ jako zúžení (nebo explicitní) převod. 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 n-tic 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ě tuply mají pro pole různé názvy.

Všechny čtyři z těchto n-tic mají stejný počet polí (označovaný jako "srovnatelnost") a typy těchto polí jsou shodné. Proto všechna tato zadání 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 n-tic nejsou přiřazeny. Hodnoty polí jsou přiřazeny podle pořadí polí v n-tici.

Nakonec si všimněte, že n-tici named můžeme přiřadit conversion, i když první pole named je Integer a první pole conversion je Long. Toto přiřazení je úspěšné, protože převod z Integer na Long je 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)

N-tice s různým počtem 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

N-tice jako návratové hodnoty metod

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 výkonovou režii spojenou s vytvořením instance proměnné a riziko, že neúmyslně přepíšete hodnotu proměnné, kterou předává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 vracejí hodnotu, která označuje, zda byla operace parsování ú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á metoda Integer.TryParse a vrátí pojmenovanou n-tici 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 n-tic jsou vlastnosti pojmenované Item1, Item2, a tak dále. V jazyce Visual Basic n-ticích a typech ValueTuple jsou prvky n-tice pole.

  • Nelze přiřadit smysluplné názvy k prvkům instance Tuple nebo instance ValueTuple. Visual Basic umožňuje přiřadit názvy, které komunikují význam polí.

  • Vlastnosti instance n-tice jsou jen pro čtení; n-tice jsou neměnné. V jazyce Visual Basic jsou pole v tuply a v typech ValueTuple čitelné i zapisovatelné; tuply jsou proměnlivé.

  • Obecné typy n-tice jsou odkazové typy. Použití těchto řazených typů znamená přidělování objektů. Na horkých cestách to může mít měřitelný dopad na výkon vaší aplikace. N-tice v jazyce Visual Basic a typy ValueTuple jsou typy hodnot.

Rozšiřující metody ve třídě TupleExtensions usnadňují převod mezi n-ticemi jazyka Visual Basic a .NET Tuple objekty. Metoda ToTuple převede Visual Basic n-tici na objekt .NET Tuple, a metoda ToValueTuple převede objekt Tuple .NET na Visual Basic n-tici.

Následující příklad vytvoří n-tici, převede ji na .NET Tuple objekt a převede ji zpět na n-tici jazyka Visual Basic. Příklad pak porovná tuto n-tici s původní n-ticí, aby se zajistilo, že jsou si rovné.

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

Viz také