Kolekce (Visual Basic)

U mnoha aplikací chcete vytvářet a spravovat skupiny souvisejících objektů. Existují dva způsoby, jak seskupit objekty: vytvořením polí objektů a vytvořením kolekcí objektů.

Pole jsou nejužitečnější při vytváření a práci s pevným počtem objektů silného typu. Informace o polích naleznete v tématu Pole.

Kolekce poskytují flexibilnější způsob práce se skupinami objektů. Na rozdíl od polí může skupina objektů, se kterými pracujete, dynamicky zvětšovat a zmenšovat podle potřeb aplikace. U některých kolekcí můžete přiřadit klíč k libovolnému objektu, který vložíte do kolekce, abyste mohli objekt rychle načíst pomocí klíče.

Kolekce je třída, takže musíte deklarovat instanci třídy před přidáním prvků do této kolekce.

Pokud kolekce obsahuje prvky pouze jednoho datového typu, můžete použít jednu z tříd v System.Collections.Generic oboru názvů. Obecná kolekce vynucuje bezpečnost typů, aby do ní nelze přidat žádný jiný datový typ. Když načtete prvek z obecné kolekce, nemusíte určit jeho datový typ ani jej převést.

Poznámka:

Příklady v tomto tématu obsahují příkazy Imports pro obory System.Collections.Generic názvů a System.Linq obory názvů.

Používání jednoduché kolekce

Příklady v této části používají obecnou List<T> třídu, která umožňuje pracovat se seznamem objektů silného typu.

Následující příklad vytvoří seznam řetězců a pak iteruje řetězce pomocí příkazu For Each... Další příkaz.

' Create a list of strings.
Dim salmons As New List(Of String)
salmons.Add("chinook")
salmons.Add("coho")
salmons.Add("pink")
salmons.Add("sockeye")

' Iterate through the list.
For Each salmon As String In salmons
    Console.Write(salmon & " ")
Next
'Output: chinook coho pink sockeye

Pokud je obsah kolekce známý předem, můžete k inicializaci kolekce použít inicializátor kolekce. Další informace naleznete v tématu Inicializátory kolekce.

Následující příklad je stejný jako předchozí příklad, s výjimkou inicializátoru kolekce se používá k přidání elementů do kolekce.

' Create a list of strings by using a
' collection initializer.
Dim salmons As New List(Of String) From
    {"chinook", "coho", "pink", "sockeye"}

For Each salmon As String In salmons
    Console.Write(salmon & " ")
Next
'Output: chinook coho pink sockeye

Můžete použít for ... Další příkaz místo For Each příkazu, který bude iterovat kolekcí. Toho dosáhnete přístupem k prvkům kolekce podle pozice indexu. Index prvků začíná na 0 a končí počtem prvků minus 1.

Následující příklad iteruje prvky kolekce pomocí namísto For…NextFor Each.

Dim salmons As New List(Of String) From
    {"chinook", "coho", "pink", "sockeye"}

For index = 0 To salmons.Count - 1
    Console.Write(salmons(index) & " ")
Next
'Output: chinook coho pink sockeye

Následující příklad odebere prvek z kolekce zadáním objektu, který se má odebrat.

' Create a list of strings by using a
' collection initializer.
Dim salmons As New List(Of String) From
    {"chinook", "coho", "pink", "sockeye"}

' Remove an element in the list by specifying
' the object.
salmons.Remove("coho")

For Each salmon As String In salmons
    Console.Write(salmon & " ")
Next
'Output: chinook pink sockeye

Následující příklad odebere elementy z obecného seznamu. For Each Místo příkazu, for... Použije se další příkaz, který iteruje v sestupném pořadí. Důvodem je to, že metoda způsobí, že RemoveAt prvky po odebrání elementu mají nižší hodnotu indexu.

Dim numbers As New List(Of Integer) From
    {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}

' Remove odd numbers.
For index As Integer = numbers.Count - 1 To 0 Step -1
    If numbers(index) Mod 2 = 1 Then
        ' Remove the element by specifying
        ' the zero-based index in the list.
        numbers.RemoveAt(index)
    End If
Next

' Iterate through the list.
' A lambda expression is placed in the ForEach method
' of the List(T) object.
numbers.ForEach(
    Sub(number) Console.Write(number & " "))
' Output: 0 2 4 6 8

Pro typ prvků v sadě List<T>můžete také definovat vlastní třídu. V následujícím příkladu Galaxy je třída, kterou používá, List<T> definována v kódu.

Private Sub IterateThroughList()
    Dim theGalaxies As New List(Of Galaxy) From
        {
            New Galaxy With {.Name = "Tadpole", .MegaLightYears = 400},
            New Galaxy With {.Name = "Pinwheel", .MegaLightYears = 25},
            New Galaxy With {.Name = "Milky Way", .MegaLightYears = 0},
            New Galaxy With {.Name = "Andromeda", .MegaLightYears = 3}
        }

    For Each theGalaxy In theGalaxies
        With theGalaxy
            Console.WriteLine(.Name & "  " & .MegaLightYears)
        End With
    Next

    ' Output:
    '  Tadpole  400
    '  Pinwheel  25
    '  Milky Way  0
    '  Andromeda  3
End Sub

Public Class Galaxy
    Public Property Name As String
    Public Property MegaLightYears As Integer
End Class

Typy kolekcí

Rozhraní .NET Framework poskytuje řadu běžných kolekcí. Každý typ kolekce je určený pro konkrétní účel.

Některé běžné třídy kolekcí jsou popsány v této části:

Třídy System.Collections.Generic

Obecnou kolekci můžete vytvořit pomocí jedné z tříd v System.Collections.Generic oboru názvů. Obecná kolekce je užitečná, když má každá položka v kolekci stejný datový typ. Obecná kolekce vynucuje silné psaní tím, že umožňuje přidání pouze požadovaného datového typu.

Následující tabulka uvádí některé často používané třídy System.Collections.Generic oboru názvů:

Třída Popis
Dictionary<TKey,TValue> Představuje kolekci párů klíč/hodnota uspořádaných na základě klíče.
List<T> Představuje seznam objektů, ke kterým lze přistupovat pomocí indexu. Poskytuje metody pro vyhledávání, řazení a úpravy seznamů.
Queue<T> Představuje první kolekci objektů fiFO (first out).
SortedList<TKey,TValue> Představuje kolekci párů klíč/hodnota seřazených podle klíče na základě přidružené IComparer<T> implementace.
Stack<T> Představuje poslední kolekci objektů (LIFO).

Další informace naleznete v tématu Běžně používané typy kolekcí, výběr třídy kolekce a System.Collections.Generic.

Třídy System.Collections.Concurrent

V rozhraní .NET Framework 4 nebo novějších poskytují kolekce v System.Collections.Concurrent oboru názvů efektivní operace bezpečné pro přístup k položkám kolekce z více vláken.

Třídy v System.Collections.Concurrent oboru názvů by měly být použity místo odpovídajících typů v oboru System.Collections.Generic názvů a System.Collections vždy, když více vláken přistupuje ke kolekci současně. Další informace naleznete v tématu Thread-Sejf Kolekce a System.Collections.Concurrent.

Některé třídy zahrnuté v System.Collections.Concurrent oboru názvů jsou BlockingCollection<T>, ConcurrentDictionary<TKey,TValue>, ConcurrentQueue<T>a ConcurrentStack<T>.

Třídy System.Collections

Třídy v System.Collections oboru názvů neukládají elementy jako objekty s konkrétním typem, ale jako objekty typu Object.

Kdykoli je to možné, měli byste místo starších typů v oboru názvů použít obecné kolekce v System.Collections.Generic oboru názvů nebo System.Collections.Concurrent obor System.Collections názvů.

Následující tabulka uvádí některé často používané třídy v System.Collections oboru názvů:

Třída Popis
ArrayList Představuje pole objektů, jejichž velikost je dynamicky zvýšena podle potřeby.
Hashtable Představuje kolekci párů klíč-hodnota uspořádaných podle hodnot hash klíčů.
Queue Představuje první kolekci objektů fiFO (first out).
Stack Představuje poslední kolekci objektů (LIFO).

Obor System.Collections.Specialized názvů poskytuje specializované a silně typované třídy kolekcí, jako jsou kolekce pouze řetězce a propojené seznamy a hybridní slovníky.

Třída Collection v jazyce Visual Basic

Třídu Jazyka Visual Basic Collection můžete použít pro přístup k položce kolekce pomocí číselného indexu String nebo klíče. Položky můžete do objektu kolekce přidat buď pomocí klíče, nebo bez zadání klíče. Pokud přidáte položku bez klíče, musíte pro přístup k ní použít jeho číselný index.

Třída Jazyka Visual Basic Collection ukládá všechny jeho prvky jako typ Object, takže můžete přidat položku libovolného datového typu. Neexistuje žádná ochrana proti přidání nevhodných datových typů.

Při použití třídy Visual Basic Collection má první položka v kolekci index 1. Liší se od tříd kolekce rozhraní .NET Framework, pro které je počáteční index 0.

Kdykoli je to možné, měli byste místo třídy Visual Basic Collection použít obecné kolekce v System.Collections.Generic oboru názvů nebo System.Collections.Concurrent oboru názvů.

Další informace najdete na webu Collection.

Implementace kolekce párů klíč/hodnota

Obecná Dictionary<TKey,TValue> kolekce umožňuje přístup k prvkům v kolekci pomocí klíče každého prvku. Každý doplněk slovníku se skládá z hodnoty a jeho přidruženého klíče. Načtení hodnoty pomocí klíče je rychlé, protože Dictionary třída je implementována jako hashovací tabulka.

Následující příklad vytvoří Dictionary kolekci a iteruje prostřednictvím slovníku For Each pomocí příkazu.

Private Sub IterateThroughDictionary()
    Dim elements As Dictionary(Of String, Element) = BuildDictionary()

    For Each kvp As KeyValuePair(Of String, Element) In elements
        Dim theElement As Element = kvp.Value

        Console.WriteLine("key: " & kvp.Key)
        With theElement
            Console.WriteLine("values: " & .Symbol & " " &
                .Name & " " & .AtomicNumber)
        End With
    Next
End Sub

Private Function BuildDictionary() As Dictionary(Of String, Element)
    Dim elements As New Dictionary(Of String, Element)

    AddToDictionary(elements, "K", "Potassium", 19)
    AddToDictionary(elements, "Ca", "Calcium", 20)
    AddToDictionary(elements, "Sc", "Scandium", 21)
    AddToDictionary(elements, "Ti", "Titanium", 22)

    Return elements
End Function

Private Sub AddToDictionary(ByVal elements As Dictionary(Of String, Element),
ByVal symbol As String, ByVal name As String, ByVal atomicNumber As Integer)
    Dim theElement As New Element

    theElement.Symbol = symbol
    theElement.Name = name
    theElement.AtomicNumber = atomicNumber

    elements.Add(Key:=theElement.Symbol, value:=theElement)
End Sub

Public Class Element
    Public Property Symbol As String
    Public Property Name As String
    Public Property AtomicNumber As Integer
End Class

Chcete-li místo toho použít inicializátor kolekce k sestavení Dictionary kolekce, můžete nahradit BuildDictionary a AddToDictionary metody následující metodou.

Private Function BuildDictionary2() As Dictionary(Of String, Element)
    Return New Dictionary(Of String, Element) From
        {
            {"K", New Element With
                {.Symbol = "K", .Name = "Potassium", .AtomicNumber = 19}},
            {"Ca", New Element With
                {.Symbol = "Ca", .Name = "Calcium", .AtomicNumber = 20}},
            {"Sc", New Element With
                {.Symbol = "Sc", .Name = "Scandium", .AtomicNumber = 21}},
            {"Ti", New Element With
                {.Symbol = "Ti", .Name = "Titanium", .AtomicNumber = 22}}
        }
End Function

Následující příklad používá metodu ContainsKeyItem[] a vlastnost Dictionary k rychlému vyhledání položky podle klíče. Tato Item vlastnost umožňuje přístup k položce v elements kolekci pomocí elements(symbol) kódu v jazyce Visual Basic.

Private Sub FindInDictionary(ByVal symbol As String)
    Dim elements As Dictionary(Of String, Element) = BuildDictionary()

    If elements.ContainsKey(symbol) = False Then
        Console.WriteLine(symbol & " not found")
    Else
        Dim theElement = elements(symbol)
        Console.WriteLine("found: " & theElement.Name)
    End If
End Sub

Následující příklad místo toho používá metodu TryGetValue rychle najít položku podle klíče.

Private Sub FindInDictionary2(ByVal symbol As String)
    Dim elements As Dictionary(Of String, Element) = BuildDictionary()

    Dim theElement As Element = Nothing
    If elements.TryGetValue(symbol, theElement) = False Then
        Console.WriteLine(symbol & " not found")
    Else
        Console.WriteLine("found: " & theElement.Name)
    End If
End Sub

Přístup ke kolekci pomocí jazyka LINQ

LINQ (language-integrated Query) se dá použít pro přístup k kolekcím. Dotazy LINQ poskytují možnosti filtrování, řazení a seskupování. Další informace naleznete v tématu Začínáme s LINQ v jazyce Visual Basic.

Následující příklad spustí dotaz LINQ na obecný List. Dotaz LINQ vrátí jinou kolekci, která obsahuje výsledky.

Private Sub ShowLINQ()
    Dim elements As List(Of Element) = BuildList()

    ' LINQ Query.
    Dim subset = From theElement In elements
                  Where theElement.AtomicNumber < 22
                  Order By theElement.Name

    For Each theElement In subset
        Console.WriteLine(theElement.Name & " " & theElement.AtomicNumber)
    Next

    ' Output:
    '  Calcium 20
    '  Potassium 19
    '  Scandium 21
End Sub

Private Function BuildList() As List(Of Element)
    Return New List(Of Element) From
        {
            {New Element With
                {.Symbol = "K", .Name = "Potassium", .AtomicNumber = 19}},
            {New Element With
                {.Symbol = "Ca", .Name = "Calcium", .AtomicNumber = 20}},
            {New Element With
                {.Symbol = "Sc", .Name = "Scandium", .AtomicNumber = 21}},
            {New Element With
                {.Symbol = "Ti", .Name = "Titanium", .AtomicNumber = 22}}
        }
End Function

Public Class Element
    Public Property Symbol As String
    Public Property Name As String
    Public Property AtomicNumber As Integer
End Class

Řazení kolekce

Následující příklad znázorňuje postup řazení kolekce. Příklad seřadí instance Car třídy, které jsou uloženy v objektu List<T>. Třída Car implementuje IComparable<T> rozhraní, které vyžaduje, aby CompareTo byla metoda implementována.

Každé volání CompareTo metody vytvoří jedno porovnání, které se používá k řazení. Uživatelem napsaný kód v CompareTo metodě vrátí hodnotu pro každé porovnání aktuálního objektu s jiným objektem. Vrácená hodnota je menší než nula, pokud je aktuální objekt menší než druhý objekt, větší než nula, pokud je aktuální objekt větší než druhý objekt, a nula, pokud jsou stejné. To umožňuje definovat v kódu kritéria pro větší než, menší než a rovno.

ListCars Příkaz v cars.Sort() metodě seřadí seznam. Toto volání Sort metody způsobí, CompareTo že metoda bude volána automaticky pro Car objekty v objektu ListList<T> .

Public Sub ListCars()

    ' Create some new cars.
    Dim cars As New List(Of Car) From
    {
        New Car With {.Name = "car1", .Color = "blue", .Speed = 20},
        New Car With {.Name = "car2", .Color = "red", .Speed = 50},
        New Car With {.Name = "car3", .Color = "green", .Speed = 10},
        New Car With {.Name = "car4", .Color = "blue", .Speed = 50},
        New Car With {.Name = "car5", .Color = "blue", .Speed = 30},
        New Car With {.Name = "car6", .Color = "red", .Speed = 60},
        New Car With {.Name = "car7", .Color = "green", .Speed = 50}
    }

    ' Sort the cars by color alphabetically, and then by speed
    ' in descending order.
    cars.Sort()

    ' View all of the cars.
    For Each thisCar As Car In cars
        Console.Write(thisCar.Color.PadRight(5) & " ")
        Console.Write(thisCar.Speed.ToString & " ")
        Console.Write(thisCar.Name)
        Console.WriteLine()
    Next

    ' Output:
    '  blue  50 car4
    '  blue  30 car5
    '  blue  20 car1
    '  green 50 car7
    '  green 10 car3
    '  red   60 car6
    '  red   50 car2
End Sub

Public Class Car
    Implements IComparable(Of Car)

    Public Property Name As String
    Public Property Speed As Integer
    Public Property Color As String

    Public Function CompareTo(ByVal other As Car) As Integer _
        Implements System.IComparable(Of Car).CompareTo
        ' A call to this method makes a single comparison that is
        ' used for sorting.

        ' Determine the relative order of the objects being compared.
        ' Sort by color alphabetically, and then by speed in
        ' descending order.

        ' Compare the colors.
        Dim compare As Integer
        compare = String.Compare(Me.Color, other.Color, True)

        ' If the colors are the same, compare the speeds.
        If compare = 0 Then
            compare = Me.Speed.CompareTo(other.Speed)

            ' Use descending order for speed.
            compare = -compare
        End If

        Return compare
    End Function
End Class

Definice vlastní kolekce

Kolekci můžete definovat implementací IEnumerable<T> nebo IEnumerable rozhraním. Další informace najdete v tématu Vytvoření výčtu kolekce.

I když můžete definovat vlastní kolekci, je obvykle lepší místo toho použít kolekce, které jsou součástí rozhraní .NET Framework, které jsou popsány v typech kolekcí dříve v tomto tématu.

Následující příklad definuje vlastní třídu kolekce s názvem AllColors. Tato třída implementuje IEnumerable rozhraní, které vyžaduje, aby GetEnumerator byla metoda implementována.

Metoda GetEnumerator vrátí instanci ColorEnumerator třídy. ColorEnumerator implementuje IEnumerator rozhraní, které vyžaduje implementaci Current vlastnosti, MoveNext metody a Reset metody.

Public Sub ListColors()
    Dim colors As New AllColors()

    For Each theColor As Color In colors
        Console.Write(theColor.Name & " ")
    Next
    Console.WriteLine()
    ' Output: red blue green
End Sub

' Collection class.
Public Class AllColors
    Implements System.Collections.IEnumerable

    Private _colors() As Color =
    {
        New Color With {.Name = "red"},
        New Color With {.Name = "blue"},
        New Color With {.Name = "green"}
    }

    Public Function GetEnumerator() As System.Collections.IEnumerator _
        Implements System.Collections.IEnumerable.GetEnumerator

        Return New ColorEnumerator(_colors)

        ' Instead of creating a custom enumerator, you could
        ' use the GetEnumerator of the array.
        'Return _colors.GetEnumerator
    End Function

    ' Custom enumerator.
    Private Class ColorEnumerator
        Implements System.Collections.IEnumerator

        Private _colors() As Color
        Private _position As Integer = -1

        Public Sub New(ByVal colors() As Color)
            _colors = colors
        End Sub

        Public ReadOnly Property Current() As Object _
            Implements System.Collections.IEnumerator.Current
            Get
                Return _colors(_position)
            End Get
        End Property

        Public Function MoveNext() As Boolean _
            Implements System.Collections.IEnumerator.MoveNext
            _position += 1
            Return (_position < _colors.Length)
        End Function

        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            _position = -1
        End Sub
    End Class
End Class

' Element class.
Public Class Color
    Public Property Name As String
End Class

Iterátory

Iterátor slouží k provedení vlastní iterace v kolekci. Iterátorem může být metoda nebo get příslušenství. Iterátor používá příkaz Yield k vrácení každého prvku kolekce po jednom.

Iterátor můžete volat pomocí příkazu For Each... Další příkaz. Každá iterace smyčky For Each volá iterátor. Yield Při dosažení příkazu v iterátoru se vrátí výraz a aktuální umístění v kódu se zachová. Spuštění se restartuje z daného umístění při příštím volání iterátoru.

Další informace najdete v tématu Iterátory (Visual Basic).

Následující příklad používá metodu iterátoru. Metoda iterátoru má Yield příkaz, který je uvnitř objektu For... Další smyčka. ListEvenNumbers V metodě každá iterace For Each těla příkazu vytvoří volání metody iterátoru, která pokračuje k dalšímu Yield příkazu.

Public Sub ListEvenNumbers()
    For Each number As Integer In EvenSequence(5, 18)
        Console.Write(number & " ")
    Next
    Console.WriteLine()
    ' Output: 6 8 10 12 14 16 18
End Sub

Private Iterator Function EvenSequence(
ByVal firstNumber As Integer, ByVal lastNumber As Integer) _
As IEnumerable(Of Integer)

' Yield even numbers in the range.
    For number = firstNumber To lastNumber
        If number Mod 2 = 0 Then
            Yield number
        End If
    Next
End Function

Viz také