Kolekce jsou velmi šikovný nástroj pro správu většího množství dat stejného druhu. Pro příklad, který jste uvedl je ale nutné pochopit, jaký je rozdíl mezi referencí a hodnotou. REFERENCE
Public Sub Test()
Dim a = New TextBox()
Dim b = New TextBox()
' přiřadíme do a REFERENCI b (na a už nic neodkazuje, zapomene se, smaže ho Garbage Collector)
a = b (a = ref. na 2. TB, b = ref. na 2. TB)
' změníme a
a.Text = "test" (a.Text = "test", b.Text = "test")
' změna se promítne do b
' protože obě proměnné ukazovali na jeden objekt (a = b)
End Sub
Co je to Garbage Collector a vůbec detailnější popis nabízí tento web v seriálu článků o základech VB .NET. HODNOTA
Public Sub Test()
Dim a = 1
Dim b = 2
' přiřadíme do a HODNOTU b
a = b (a = 2, b = 2)
' změníme a
a = 4 (a = 4, b = 2)
' změna se nepromítne do b
' obě proměnné měli svou hodnotu
End Sub
Reference je v podstatě celé číslo (32 nebo 64bitové, záleží na systému), které ukazuje na nějaké místo na haldě (ang. Heap), což je místo, kam si CLR Runtime (běhové prostředí .NET Frameworku) ukládá referenční typy a reference jsou odkazy na to místo, které vedou na konkrétní objekty. To znamená, že pokud uděláte kolekci hodnotových typů (Integer, Double, atd.) a změníte jeden prvek, v ostatních se to neprojeví (změníte hodnotu). Pokud uděláte kolekci referenčních typů (tříd, jako například TextBox):
Dim list = New System.Collections.Generic.List(Of TextBox)
Dim tb1 = new TextBox()
Dim tb2 = New TextBox() With {.Text = "bla"}
list.Add(tb1)
list.Add(tb1)
list.Add(tb2)
A takto jí naplníte (máte tam dvě reference na první TextBox a jednu reference na druhý TextBox), budou jejich vlastnosti vypadat takto:
list(0).Text = ""
list(1).Text = ""
list(2).Text = "bla"
Pokud změníte objekt na který odkazuje první (nebo druhá, jsou stejné) reference:
list(0).Text = "test?"
Změny se narozdíl od hodnotových typů promítnou na referencovaném objektu a všechny reference je budou reflektovat:
list(0).Text = "test?"
list(1).Text = "test?"
list(2).Text = "bla"
Nyní přichází ta důležitá část. String je sice referenční typ, ale pracuje velmi zvláštně. Je Immutable, což znamená, že pokud ho změníte, vytvoří se jeho nová Instance, tedy nová reference na nový objekt String. V praxi to tedy působí, jako by byl hodnotový. Muttable (měnitelná) verze Stringu je System.Text.StringBuilder, který zachovává pořád stejnou referenci při jeho změnách a až na konečné zavolání .ToString() vrací finální String, který je už opět Immutable. Tomáš Herceg má na svém blogu hezký článek o tom, proč se obzvláště u větších (delších) textů vyplatí používat StringBuilder namísto String. http://www.vbnet.cz/blog-clanek--355-pro... Není tedy dobrý nápad v kolekci odkazovat na TextBox.Text, ale přímo na TextBox:
Public Sub Form1_Load(...) Handles MyBase.Load
Me.Controls.Add(New TextBox())
Me.Controls.Add(New TextBox())
Me.Controls.Add(New TextBox())
Dim kolekce = Me.Controls.OfType(Of TextBox)()
' toto volání vrátí kolekci prvků na formuláři, jež jsou typu TextBox
kolekce(0).Text = "test?"
End Sub
Po spuštění formuláře by se měl Text prvního TextBoxu změnit na "test?". Celé kouzlu spočívá v tom, že s kolekcemi se vyhnete tomuto:
Dim proměnná1 = 1
Dim proměnní2 = 2
Dim proměnná3 = 3
Prostě to nahradíte kolekcí:
Dim proměnné = New List(Of Integer)({1,2,3})
' nebo
Dim proměnné = New List(Of Integer) From {1,2,3}
' From klauzule automaticky volá .Add proceduru s prvky v poli {}
Existují také další typy kolekcí, jako Stack(Of T), která funguje tak, že první prvek, který tam vložíte, jako poslední zase dostanete (LIFO last-in-first-out), takže:
Dim stack As New Stack(Of Integer)
stack.Push(1)
stack.Push(2)
stack.Pop() ' 2
stack.Pop() ' 1
Tato kolekce je velmi užitečná při práci s rekurzí. Nebo Queue(Of T) (FIFO first-in-first-out), která funguje tak, že první vložený prvek je první výstupní prvek:
Dim queue As New Queue(Of Integer)
queue.Enqueue(1)
queue.Enqueue(2)
queue.Dequeue() ' 1
queue.Dequeue() ' 2
A v neposlední řadě, slovník Dictionary(Of TKey, TValue), kolekce klíč hodnota (unikátní klíč):
Dim dictionary As New Dictionary(Of String, Person)
dictionary.Add("Alex Clarai", New Person("Alex", "Clarai"))
dictionary("Alex Clarai").Birthdate = Date.Now()
Slovník je velmi rychlá záležitost, protože klíč interně hashuje, takže vyhledávání v něm probíhá rychlostí blesku. Mimochodem i se slovníkem je možné využívat From klauzuli, stačí mít na paměti, že potřebujeme slovník plnit páry klíč-hodnota:
Dim dictionary As New Dictionary(Of Integer, String) From {{1,"jedna"},{2,"dvě"}}
Snad jsem to popsal srozumitelně, pro pochopení rozdílu mezi hodnotou a referencí a hlavně pro pochopení, k čemu je to dobré a kdy to bude jak fungovat, je třeba dost praxe s programování. Pokud si zvyknete kolekce používat, uvidíte, že Vám v budoucnu budou velmi k dobru.
|