Lekce 1 - Úvod do kolekcí a genericita
V dnešní lekci si řekneme úvodní teorii ke kolekcím ve VB.NET, které si v tomto kurzu podrobněji rozebereme.
Kolekce
Pojem kolekce označuje soubor dat, které jsou většinou
stejného typu a slouží ke specifickému účelu. Během
seriálu jsme se již setkali se dvěma typy kolekcí, bylo to pole a
List
. Kolekcí existuje velké množství a ačkoli se zvenku
mnohdy tváří podobně, uvnitř fungují velmi odlišně a vybíráme si je
podle konkrétního účelu. .NET disponuje velkým množstvím
předpřipravených kolekcí, se kterými se v této sekci postupně seznámíme
a zkusíme si s nimi pracovat.
Generické a obecné kolekce
Když se zamyslíme nad tím, jak bychom si udělali vlastní kolekci, jistě
bychom po nějaké době dospěli k problému. Byl by jím datový
typ kolekce. Chtěli bychom si např. naprogramovat vlastní
List
, vytvořili bychom třídu MujList.vb
, do ní
přidali příslušné metody a vše potřebné. Protože však chceme, aby byla
naše kolekce univerzální a uměla tedy ukládat např. jak
Integer
, tak uživatele, bude problém s datovým typem prvků
uvnitř kolekce. Existují dvě varianty, jak tento problém vyřešit a i
samotný .NET obsahuje kolekce těchto dvou typů.
Obecné kolekce
Jelikož víme, že všechny datové typy mají jako předka
třídu Object
, můžeme prvky v naší kolekci ukládat právě do
tohoto datového typu. Do kolekce nyní můžeme uložit v podstatě cokoli.
Nevýhodou je, že sama kolekce skutečný datový typ prvků nezná a proto
umí prvky navracet jen jako obecné objekty. Po získání prvku z kolekce si
jej tedy musíme přetypovat.
Uveďme si příklad negenerické kolekce, je jí ArrayList
:
Dim list As New ArrayList() list.Add("položka") Dim polozka As String = CType(list(0), String) Console.WriteLine(polozka) Výstup programu:
Konzolová aplikace
položka
Po vytvoření listu si do něj přidáme položku typu String
.
Abychom tuto položku mohli z Listu získat zpět, je třeba ji na
String
zpětně přetypovat.
Pro funkčnost kódu musíme přidat Imports System.Collections
.
Jelikož tento jmenný prostor není ve výchozím projektu přítomen,
napovídá nám to, že negenerické kolekce nebudou ta obvyklá volba.
Generické kolekce
Generické kolekce řeší problém s datovým typem na úrovni jazyka
VB.NET. Zavádí tzv. genericitu. Zjednodušeně řečeno se
jedná o možnost specifikovat datový typ až ve chvíli
vytvoření instance. Ve třídě samotné kolekce se poté
pracuje s generickým typem, který slouží jako zástupce pro
budoucí datový typ. Můžeme si to představit tak, že se
generický typ ve třídě změní např. na String
ve chvíli,
když vytvoříme její instanci. Jedná se tedy o možnost třídy nějakým
způsobem parametrizovat.
Generický List
již známe a onen datový typ (parametr) se
generickým třídám specifikuje v závorkách uvozen slovem `Of `. Máme
možnost specifikovat datový typ pouze jednou, při
vytvoření kolekce. Jakékoli další přetypování
odpadá:
{VBNET_CONSOLE}
Dim list As New List(Of String)()
list.Add("položka")
Dim polozka As String = list(0)
Console.WriteLine(polozka)
{/VBNET_CONSOLE}
Výstup programu:
Konzolová aplikace
položka
Program funguje úplně stejně, jako ten s negenerickou kolekcí
ArrayList
, nicméně číst můžeme bez nepohodlného
přetypování.
Generické kolekce nahradily kolekce obecné a ty se již příliš nepoužívají. V kurzu se budeme věnovat generickým kolekcím a jejich negenerické verze pouze zmíníme.
Genericita
Genericita je samozřejmě vlastnost jazyka VB.NET a my ji máme možnost ve svých třídách používat.
Zatím se nebudeme zatěžovat tvorbou vlastní kolekce. Vytvořme si
třídu, která bude jednoduše spravovat jednu proměnnou. Proměnná bude
generická, tedy libovolného datového typu. Založíme si nový projekt,
konzolovou aplikaci s názvem Genericita
. Přidáme si novou
třídu, pojmenujme ji nyní pro studijní účely pouze Trida
. V
její deklaraci přidáme generický parametr, který pojmenujeme
T
:
Public Class Trida(Of T) End Class
Generických parametrů můžeme zadat v závorce po Of
více,
oddělíme je čárkou. Někdy se to může hodit, my se s tím setkáme dále u
generických slovníků.
Přesuneme se do metody Main()
, kde si vytvoříme instanci
naší třídy:
Dim instance As New Trida(Of Integer)(10)
Nezapomeneme na kulaté závorky a Of
jak u datového
typu, tak u konstruktoru. Nyní jsme parametru
T
v této instanci třídy určili datový typ
Integer
. Stejně tak si můžeme udělat další instanci té samé
třídy a parametru T
dát úplně jiný datový typ, např.
S
. Stačí nám tedy jedna třída pro
více datových typů.
Pokračujme a vytvořme si ve třídě atribut. T
můžeme
použít jako běžný datový typ:
Private promenna As T
Třídě ještě dodáme konstruktor, který proměnnou inicializuje:
Public Sub New(promenna As T) Me.promenna = promenna End Sub
V Main()
aktualizujeme vytvoření instance:
Dim instance As New Trida(Of Integer)(10)
Nyní instance obsahuje atribut promenna
, který je typu
Integer
a nabývá hodnoty 10
.
Můžeme dokonce přidat metodu, která bude mít navíc další generický parametr (jiný, než má třída). Mohla by vypadat např. takto:
Public Function Porovnej(Of T2)(a As T2) As Boolean Return promenna.Equals(a) End Function
Zkusíme si tedy porovnat náš Integer
s nějakým jiným
typem.
Kód třídy Program
:
Class Program Shared Sub Main(args As String()) Dim instance As New Trida(Of Integer)(10) Dim stejne As Boolean = instance.Porovnej(Of String)("15") Console.WriteLine(stejne) End Sub End Class
Kód třídy Trida
:
Public Class Trida(Of T As {IComparable, New}) Private promenna As T Public Sub New(promenna As T) Me.promenna = promenna End Sub Public Function Porovnej(Of T2)(a As T2) As Boolean Return promenna.Equals(a) End Function End Class
Výstup programu:
False
Další konstrukce
Pro úplnost si ještě uveďme několik konstrukcí.
Generický parametr třídy je možné blíže specifikovat,
přesněji omezit. Slouží k tomu složené závorky následující za
As
. Můžeme tak nastavit, že udaný datový typ musí např.
obsahovat rozhraní IComparable
:
Public Class Trida(Of T As {IComparable}) End Class
Díky tomu můžeme na proměnných typu T
nyní uvnitř třídy
volat metody z daného rozhraní. Samotné rozhraní může
opět obsahovat generický parametr, abychom generické typy
mohli používat i v hlavičkách jeho metod.
Když uvedeme New
, můžeme uvnitř typ T
instanciovat. Taková malá továrna na instance libovolného typu by mohla
vypadat takto:
Public Class Tovarna(Of T As New) Public Function VytvorInstanci() As T Return New T() End Function End Class
Pokud máme ve {}
již nějaká rozhraní,
New
dáme jednoduše mezi ně a oddělíme čárkou.
Nakonec si ukažme, jak můžeme typ parametru omezit z hlediska dědičnosti:
Public Class Trida(Of A As B, B As C, C) End Class
Výše jsme deklarovali třídu se třemi generickými parametry, kde
A
je potomkem B
a B
je potomkem
C
.
V příští lekci, Seznam (List) pomocí pole ve VB.NET, se podíváme na listy, představíme si různé implementace této kolekce a jejich výhody a nevýhody.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 9x (256.43 kB)
Aplikace je včetně zdrojových kódů v jazyce VB