L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Raccolte (Visual Basic)
Articolo
03/04/2024
Per molte applicazioni è utile creare e gestire gruppi di oggetti correlati. È possibile raggruppare gli oggetti in due modi: creando matrici di oggetti e creando raccolte di oggetti.
Le matrici sono estremamente utili per la creazione e l'uso di un numero fisso di oggetti fortemente tipizzati. Per altre informazioni sulle matrici, vedere Matrici.
Le raccolte consentono di lavorare in modo più flessibile con gruppi di oggetti. A differenza delle matrici, il gruppo di oggetti con cui si lavora può aumentare e diminuire in modo dinamico in base alle esigenze dell'applicazione. Per alcune raccolte è possibile assegnare una chiave a qualsiasi oggetto inserito nella raccolta in modo da recuperare rapidamente l'oggetto usando la chiave.
Una raccolta è una classe. Di conseguenza, prima di poter aggiungere elementi a una nuova raccolta è necessario dichiarare la raccolta.
Se la raccolta contiene elementi di un solo tipo di dati, è possibile usare una delle classi dello spazio dei nomi System.Collections.Generic. In una raccolta generica viene imposta l'indipendenza dai tipi, in modo da impedire che vengano aggiunti altri tipi di dati alla raccolta. Quando si recupera un elemento da una raccolta generica, non è necessario determinarne il tipo di dati né convertirlo.
Nota
Per gli esempi in questo argomento, includere le istruzioni Imports per gli spazi dei nomi System.Collections.Generic e System.Linq.
Uso di una raccolta semplice
Gli esempi in questa sezione usano la classe generica List<T>, che consente di usare un elenco di oggetti fortemente tipizzato.
L'esempio seguente crea un elenco di stringhe, quindi esegue l'iterazione nelle stringhe usando un'istruzione For Each...Next.
VB
' Create a list of strings.Dim salmons AsNew List(OfString)
salmons.Add("chinook")
salmons.Add("coho")
salmons.Add("pink")
salmons.Add("sockeye")
' Iterate through the list.ForEach salmon AsStringIn salmons
Console.Write(salmon & " ")
Next'Output: chinook coho pink sockeye
Se il contenuto di una raccolta è noto in anticipo, si può usare un inizializzatore di raccolta per inizializzare la raccolta. Per altre informazioni, vedere Inizializzatori di insieme.
L'esempio seguente è identico all'esempio precedente, ma usa un inizializzatore di raccolta per aggiungere elementi alla raccolta.
VB
' Create a list of strings by using a' collection initializer.Dim salmons AsNew List(OfString) From
{"chinook", "coho", "pink", "sockeye"}
ForEach salmon AsStringIn salmons
Console.Write(salmon & " ")
Next'Output: chinook coho pink sockeye
È possibile usare un'istruzione For...Next anziché un'istruzione For Each per eseguire l'iterazione in una raccolta. Questo è possibile mediante l'accesso agli elementi della raccolta dalla posizione di indice. L'indice degli elementi inizia da 0 e termina in corrispondenza del numero di elementi meno 1.
Nell'esempio seguente l'iterazione negli elementi di una raccolta avviene mediante For…Next anziché mediante For Each.
VB
Dim salmons AsNew List(OfString) From
{"chinook", "coho", "pink", "sockeye"}
For index = 0To salmons.Count - 1
Console.Write(salmons(index) & " ")
Next'Output: chinook coho pink sockeye
Nell'esempio seguente viene rimosso un elemento dalla raccolta specificando l'oggetto da rimuovere.
VB
' Create a list of strings by using a' collection initializer.Dim salmons AsNew List(OfString) From
{"chinook", "coho", "pink", "sockeye"}
' Remove an element in the list by specifying' the object.
salmons.Remove("coho")
ForEach salmon AsStringIn salmons
Console.Write(salmon & " ")
Next'Output: chinook pink sockeye
Nell'esempio seguente vengono rimossi elementi da un elenco generico. Invece di un'istruzione For Each viene usata un'istruzione For...Next che esegue l'iterazione in ordine decrescente. Ciò è necessario perché il metodo RemoveAt fa sì che gli elementi dopo un elemento rimosso abbiano un valore di indice inferiore.
VB
Dim numbers AsNew List(OfInteger) From
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
' Remove odd numbers.For index AsInteger = numbers.Count - 1To0Step-1If numbers(index) Mod2 = 1Then' Remove the element by specifying' the zero-based index in the list.
numbers.RemoveAt(index)
EndIfNext' 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
Per il tipo di elementi in List<T>, è possibile anche definire una classe personalizzata. Nell'esempio seguente la classe Galaxy viene usata dall'oggetto List<T> definito nel codice.
VB
PrivateSub IterateThroughList()
Dim theGalaxies AsNew 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}
}
ForEach theGalaxy In theGalaxies
With theGalaxy
Console.WriteLine(.Name & " " & .MegaLightYears)
EndWithNext' Output:' Tadpole 400' Pinwheel 25' Milky Way 0' Andromeda 3EndSubPublicClass Galaxy
PublicProperty Name AsStringPublicProperty MegaLightYears AsIntegerEndClass
Tipi di raccolte
Molte raccolte comuni vengono fornite da .NET Framework. Ogni tipo di raccolta è progettato per uno scopo specifico.
In questa sezione sono descritte alcune classi di raccolte comuni:
È possibile creare una raccolta generica usando una delle classi dello spazio dei nomi System.Collections.Generic. Una raccolta generica è utile quando ogni elemento al suo interno presenta lo stesso tipo di dati. Una raccolta generica applica la tipizzazione forte consentendo di aggiungere soltanto i tipi di dati desiderati.
La tabella seguente elenca alcune delle classi di uso frequente dello spazio dei nomi System.Collections.Generic:
In .NET Framework 4 o versioni successive le raccolte dello spazio dei nomi System.Collections.Concurrent garantiscono operazioni thread-safe efficienti per accedere agli elementi della raccolta da più thread.
Le classi dello spazio dei nomi System.Collections non archiviano gli elementi come oggetti tipizzati in modo specifico, ma come oggetti di tipo Object.
Rappresenta una raccolta di oggetti LIFO (Last-In First-Out).
Lo spazio dei nomi System.Collections.Specialized offre classi di raccolte fortemente tipizzate e specializzate, ad esempio raccolte di sole stringhe, dizionari ibridi e dizionari a elenchi collegati.
Classe Collection di Visual Basic
È possibile usare la classe Collection di Visual Basic per accedere a un elemento della raccolta usando un indice numerico o una chiave String. Per aggiungere elementi a un oggetto raccolta, è possibile specificare o non specificare una chiave. Se si aggiunge un elemento senza una chiave, è necessario usare il relativo indice numerico per accedervi.
La classe Collection di Visual Basic archivia tutti gli elementi di tipo Object, pertanto è possibile aggiungere un elemento di qualsiasi tipo di dati. Non esiste alcuna misura per impedire l'aggiunta di tipi di dati non appropriati.
Quando si usa la classe Collection di Visual Basic, il primo elemento di una raccolta ha indice 1. Questo comportamento è diverso rispetto alle classi Collection di .NET Framework, per cui l'indice iniziale è 0.
Implementazione di una raccolta di coppie chiave/valore
La raccolta generica Dictionary<TKey,TValue> consente di accedere agli elementi di una raccolta usando la chiave di ogni elemento. Ogni aggiunta al dizionario è costituita da un valore e dalla chiave associata corrispondente. Il recupero di un valore tramite la relativa chiave è un'operazione veloce, perché la classe Dictionary viene implementata come tabella hash.
L'esempio seguente crea una raccolta Dictionary ed esegue l'iterazione nel dizionario usando un'istruzione For Each.
VB
PrivateSub IterateThroughDictionary()
Dim elements As Dictionary(OfString, Element) = BuildDictionary()
ForEach kvp As KeyValuePair(OfString, Element) In elements
Dim theElement As Element = kvp.Value
Console.WriteLine("key: " & kvp.Key)
With theElement
Console.WriteLine("values: " & .Symbol & " " &
.Name & " " & .AtomicNumber)
EndWithNextEndSubPrivateFunction BuildDictionary() As Dictionary(OfString, Element)
Dim elements AsNew Dictionary(OfString, Element)
AddToDictionary(elements, "K", "Potassium", 19)
AddToDictionary(elements, "Ca", "Calcium", 20)
AddToDictionary(elements, "Sc", "Scandium", 21)
AddToDictionary(elements, "Ti", "Titanium", 22)
Return elements
EndFunctionPrivateSub AddToDictionary(ByVal elements As Dictionary(OfString, Element),
ByVal symbol AsString, ByVal name AsString, ByVal atomicNumber AsInteger)
Dim theElement AsNew Element
theElement.Symbol = symbol
theElement.Name = name
theElement.AtomicNumber = atomicNumber
elements.Add(Key:=theElement.Symbol, value:=theElement)
EndSubPublicClass Element
PublicProperty Symbol AsStringPublicProperty Name AsStringPublicProperty AtomicNumber AsIntegerEndClass
Per usare invece un inizializzatore di raccolta per compilare la raccolta Dictionary, è possibile sostituire i metodi BuildDictionary e AddToDictionary con il metodo seguente.
VB
PrivateFunction BuildDictionary2() As Dictionary(OfString, Element)
ReturnNew Dictionary(OfString, 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}}
}
EndFunction
L'esempio seguente usa il metodo ContainsKey e la proprietà Item[] di Dictionary per trovare rapidamente un elemento in base alla chiave. La proprietà Item consente di accedere a un elemento nella raccolta elements usando il codice elements(symbol) in Visual Basic.
VB
PrivateSub FindInDictionary(ByVal symbol AsString)
Dim elements As Dictionary(OfString, Element) = BuildDictionary()
If elements.ContainsKey(symbol) = FalseThen
Console.WriteLine(symbol & " not found")
ElseDim theElement = elements(symbol)
Console.WriteLine("found: " & theElement.Name)
EndIfEndSub
L'esempio seguente usa invece il metodo TryGetValue per individuare rapidamente un elemento in base alla chiave.
VB
PrivateSub FindInDictionary2(ByVal symbol AsString)
Dim elements As Dictionary(OfString, Element) = BuildDictionary()
Dim theElement As Element = NothingIf elements.TryGetValue(symbol, theElement) = FalseThen
Console.WriteLine(symbol & " not found")
Else
Console.WriteLine("found: " & theElement.Name)
EndIfEndSub
Uso di LINQ per accedere a una raccolta
È possibile usare LINQ (Language-Integrated Query) per accedere alle raccolte. Le query LINQ forniscono funzionalità di filtro, ordinamento e raggruppamento. Per altre informazioni, vedere Introduzione a LINQ in Visual Basic.
Nell'esempio seguente viene eseguita una query LINQ su un oggetto List generico. La query LINQ restituisce una raccolta diversa che contiene i risultati.
VB
PrivateSub ShowLINQ()
Dim elements As List(Of Element) = BuildList()
' LINQ Query.Dim subset = From theElement In elements
Where theElement.AtomicNumber < 22OrderBy theElement.Name
ForEach theElement In subset
Console.WriteLine(theElement.Name & " " & theElement.AtomicNumber)
Next' Output:' Calcium 20' Potassium 19' Scandium 21EndSubPrivateFunction BuildList() As List(Of Element)
ReturnNew 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}}
}
EndFunctionPublicClass Element
PublicProperty Symbol AsStringPublicProperty Name AsStringPublicProperty AtomicNumber AsIntegerEndClass
Ordinamento di una raccolta
L'esempio seguente illustra una procedura per ordinare una raccolta. Nell'esempio vengono ordinate le istanze della classe Car archiviate in un oggetto List<T>. La classe Car implementa l'interfaccia IComparable<T>, che richiede l'implementazione del metodo CompareTo.
Ogni chiamata al metodo CompareTo effettua un confronto unico che viene usato per l'ordinamento. Il codice scritto dall'utente presente nel metodo CompareTo restituisce un valore per ogni confronto dell'oggetto corrente con un altro oggetto. Il valore restituito è minore di zero se l'oggetto corrente è inferiore all'altro oggetto, maggiore di zero se l'oggetto corrente è superiore all'altro oggetto e zero se sono uguali. In questo modo è possibile definire nel codice i criteri di maggiore, minore e uguale.
Nel metodo ListCars l'istruzione cars.Sort() ordina l'elenco. Questa chiamata al metodo Sort di List<T> determina la chiamata automatica al metodo CompareTo per gli oggetti Car in List.
VB
PublicSub ListCars()
' Create some new cars.Dim cars AsNew 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.ForEach 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 car2EndSubPublicClass Car
Implements IComparable(Of Car)
PublicProperty Name AsStringPublicProperty Speed AsIntegerPublicProperty Color AsStringPublicFunction CompareTo(ByVal other As Car) AsInteger _
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.DimcompareAsIntegercompare = String.Compare(Me.Color, other.Color, True)
' If the colors are the same, compare the speeds.Ifcompare = 0Thencompare = Me.Speed.CompareTo(other.Speed)
' Use descending order for speed.compare = -compareEndIfReturncompareEndFunctionEndClass
Sebbene sia possibile definire una raccolta personalizzata, in genere è preferibile usare le raccolte incluse in .NET Framework, descritte in Tipi di raccolte in precedenza in questo argomento.
L'esempio seguente definisce una classe di raccolte personalizzata denominata AllColors. Questa classe implementa l'interfaccia IEnumerable che richiede l'implementazione del metodo GetEnumerator.
Il metodo GetEnumerator restituisce un'istanza della classe ColorEnumerator. ColorEnumerator implementa l'interfaccia IEnumerator che richiede l'implementazione della proprietà Current e dei metodi MoveNext e Reset.
VB
PublicSub ListColors()
Dim colors AsNew AllColors()
ForEach theColor As Color In colors
Console.Write(theColor.Name & " ")
Next
Console.WriteLine()
' Output: red blue greenEndSub' Collection class.PublicClass AllColors
Implements System.Collections.IEnumerable
Private _colors() As Color =
{
New Color With {.Name = "red"},
New Color With {.Name = "blue"},
New Color With {.Name = "green"}
}
PublicFunction GetEnumerator() As System.Collections.IEnumerator _
Implements System.Collections.IEnumerable.GetEnumerator
ReturnNew ColorEnumerator(_colors)
' Instead of creating a custom enumerator, you could' use the GetEnumerator of the array.'Return _colors.GetEnumeratorEndFunction' Custom enumerator.PrivateClass ColorEnumerator
Implements System.Collections.IEnumerator
Private _colors() As Color
Private _position AsInteger = -1PublicSubNew(ByVal colors() As Color)
_colors = colors
EndSubPublicReadOnlyProperty Current() AsObject _
Implements System.Collections.IEnumerator.Current
GetReturn _colors(_position)
EndGetEndPropertyPublicFunction MoveNext() AsBoolean _
Implements System.Collections.IEnumerator.MoveNext
_position += 1Return (_position < _colors.Length)
EndFunctionPublicSub Reset() Implements System.Collections.IEnumerator.Reset
_position = -1EndSubEndClassEndClass' Element class.PublicClass Color
PublicProperty Name AsStringEndClass
Iteratori
Un iteratore viene usato per eseguire un'iterazione personalizzata in una raccolta. Un iteratore può essere un metodo o una funzione di accesso get. Un iteratore usa un'istruzione Yield per restituire ogni elemento della raccolta, uno alla volta.
Per chiamare un iteratore usare un'istruzione For Each...Next. Ogni iterazione del ciclo For Each chiama l'iteratore. Quando si raggiunge un'istruzione Yield nell'iteratore, viene restituita un'espressione e viene mantenuta la posizione corrente nel codice. L'esecuzione viene ripresa a partire da quella posizione la volta successiva che viene chiamato l'iteratore.
Nell'esempio seguente viene usato un metodo iteratore. Il metodo iteratore dispone di un'istruzione Yield all'interno di un ciclo For...Next. Nel metodo ListEvenNumbers ogni iterazione del corpo dell'istruzione For Each crea una chiamata al metodo iteratore, che procede all'istruzione Yield successiva.
VB
PublicSub ListEvenNumbers()
ForEach number AsIntegerIn EvenSequence(5, 18)
Console.Write(number & " ")
Next
Console.WriteLine()
' Output: 6 8 10 12 14 16 18EndSubPrivateIteratorFunction EvenSequence(
ByVal firstNumber AsInteger, ByVal lastNumber AsInteger) _
As IEnumerable(OfInteger)
' Yield even numbers in the range.For number = firstNumber To lastNumber
If number Mod2 = 0ThenYield number
EndIfNextEndFunction
L'origine di questo contenuto è disponibile in GitHub, in cui è anche possibile creare ed esaminare i problemi e le richieste pull. Per ulteriori informazioni, vedere la guida per i collaboratori.
Feedback su
.NET
.NET
è un progetto di open source. Selezionare un collegamento per fornire feedback: