Zamknij komunikat

Nowy Office 2013
Do góry Skomentuj

17. Typy generyczne (generics)

17. Typy generyczne (generics)

Daniel Celeda
30 maja 2006
145 488
Odsłony
Daniel Celeda
30 maja 2006
145 488
Odsłony

W .NET 2.0 Microsoft wprowadził nowe typy danych – typy generyczne. Do tej pory wszystkie elementy były przechowywane w kolekcjach jako obiekty klasy „object”. Obecnie mamy dostępną nową przestrzeń nazw „System.Collections.Generic”, w której znajdują się klasy umożliwiające deklarowanie jakiego typu elementy mają znajdować się w danej kolekcji (podobnie jak ma to miejsce w tablicach). Nadal dostępna jest przestrzeń „System.Collections”, zawierająca kolekcje niegeneryczne, tzw. ogólne.
Możemy sami tworzyć typy generyczne oraz metody je wykorzystujące. W tym artykule zajmiemy się kolekcjami.

Zalety

Główną zaletą jest przyspieszenie działania kolekcji. Podczas dodawania elementu nie jest on rzutowany na typ „object” (chyba że tego chcemy), a podczas pobierania elementu z kolekcji nie musimy z powrotem rzutować go na odpowiedni typ. Uniknięcie tych operacji przyspiesza znacznie działanie naszego programu.
Następną zaletą korzystania z typów generycznych jest unikanie wielu błędów już na etapie kompilacji. Używając np. „ArrayListy” możemy dodawać do niej obiekty różnych typów i kompilator nie uzna tego za błąd. Podczas wykonania może dojść do sytuacji, że pobierając elementy z listy i rzutując je na ten sam typ, może powstać błąd wykonania, ponieważ wcześniej dodaliśmy do listy element innego typu. Natomiast jeśli użyjemy „List” (generyczny odpowiednik „ArrayListy”) i zadeklarujemy jakiego typu elementy ma ona przechowywać, już na etapie kompilacji wskazany zostanie błąd podczas dodawania elementu o nieodpowiednim typie.

Użycie

Deklarowanie kolekcji generycznej wygląda następująco:

Kolekcja instancjaKolekcji = new Kolekcja();

Różni się więc od standardowego tym, że musimy podać typ elementów w nawiasach „<>”. Wywołując konstruktor musimy podać typ elementów jeszcze raz oraz na koniec, tak samo jak ma to miejsce w przypadku typowych elementów, parametry w nawiasach „()”.
Prosty przykład poniżej:

using System;
using System.Collections.Generic;
 
namespace KolekcjeGeneryczne
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> lista = new List<int>();
            lista.Add(2);
            lista.Add(5);
 
            int suma = lista[0] + lista[1];
 
            Console.WriteLine("Suma wynosi: " + suma);
            Console.ReadKey();
        }
    }
}

Wynik:

Zobaczmy co się stanie jeśli spróbujemy dodać do naszej listy element innego typu niż „int”.

using System;
using System.Collections.Generic;
 
namespace KolekcjeGeneryczne
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> lista = new List<int>();
            lista.Add(2);
            lista.Add("napis");
 
            int suma = lista[0] + lista[1];
 
            Console.WriteLine("Suma wynosi: " + suma);
            Console.ReadKey();
        }
    }
}

Podczas kompilacji zostaniemy powiadomieni o błędzie.

Dla porównania napiszmy program podobny do jednego z programów, które stworzyliśmy w poprzednim artykule ale tym razem z użyciem kolekcji generycznej.

using System;
using System.Collections.Generic;
 
namespace KolekcjeGeneryczne
{
    class Element
    {
        public int Liczba;
 
        public Element(int liczba)
        {
            this.Liczba = liczba;
        }
    }
 
    class Program
    {
        static void Main(string[] args)
        {
            Element element_1 = new Element(10);
            Element element_2 = new Element(20);
            Element element_3 = new Element(30);
 
            List<Element> lista = new List<Element>();
 
            lista.Add(element_1);
            lista.Add(element_2);
            lista.Add(element_3);
 
            Console.Write("Elementy: ");
            for(int i = 0; i < lista.Count; i++)
            {
                Console.Write(lista[i].Liczba + " ");
            }
 
            Console.ReadKey();
        }
    }
}

Jak widzimy tym razem nie musimy rzutować pobieranych elementów z kolekcji. Wiadomo od razu, że są one typu „Element” i mamy dostęp do atrybutu „Liczba”.

Wynik:

Dla osób zainteresowanych warto poczytać o tym jak tworzyć własne typy generyczne, jak zakładać ograniczenia na typy oraz jak deklarować szablony metod (metody generyczne).

Ćwiczenie.

Napisz program pobierający pięć liczb od użytkownika i dodający je do „List”. Następnie program sam doda liczbę „12” na miejsce o indeksie 2 oraz wypisze liczby za pomocą pętli „for”.

using System;
using System.Collections.Generic;
using System.Collections;
 
namespace Kolekcje
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> lista = new List<int>();
 
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Podaj liczbę.");
                int liczba = int.Parse(Console.ReadLine());
                lista.Add(liczba);
            }
 
            lista.Insert(2, 12);
 
            Console.Write("\nElementy: ");
            for (int i = 0; i < lista.Count; i++)
            {
                Console.Write(lista[i] + " ");
            }
 
            Console.ReadKey();
        }
    }
}

Zobacz również

Komentarze

Nie kumam
NOOB, 9 września 2007, 18:41
zgadzam się z poprzednim komentarzem o tyle, że gdybym skądinąd nie wiedział o co chodzi, to po przeczytaniu tego tekstu na pewno niczego bym nie zrozumiał.
torq314, 3 października 2007, 13:12
O ile dobrze rozumiem to ten "generic" to jest nic innego jak nieco zmodyfikowana zwykła tablica, tyle tylko że o ile w standardowych tablicach mogliśmy mieć tylko "stare" typy jak np. int, double, string, to w przypadku "list" jako "typ" możemy użyć klasę, nadal jednak wszystkie pliki w tablicy muszą być tej samej klasy. W przypadku kolekcji kolejne klasy w "tablicy" mogły być innego rodzaju. Pierwszym el. tablicy mogła być klasa "PierwszaKlasa", na drugim "DrugaKlasa" itp. Tutaj jeżeli już umieścimy jakiś typ klasy wewnątrz "list" to musimy się go trzymać do końca. Pomaga to uniknąć błędów gdybyśmy przypadkiem umiescili 2 inne klasy w tej samej tablicy generycznej (już podczas kompilacji) i przyśpiesza działanie programu. P.S. Przynajmniej ja to tak zrozumiałem. Pozdro
inny NOOBek, 7 października 2007, 17:12
z tego co widze to taka kolekcja stworzona wedlug szablonu; trzymajaca jeden typ danych jak tablica, a dajaca wiele innych kozysci jak kolekcja (-:
eh, 24 października 2007, 14:35
"Deklarowanie kolekcji generycznej wygląda następująco: Kolekcja instancjaKolekcji = new Kolekcja();" A czy autor nie zapomniał przypadkiem nawiasów trójkątnych... Kolekcja_generyczna#typ# instancjaKolekcji = new Kolekcja_generyczna#typ#();
Kot-ek, 19 listopada 2007, 12:22
Uwaga do poprzedniego komentarza. Chciałem podać prawidłową deklaracje, ale najwidoczniej w komentarzach nie można stosować nawiasów klamrowych... więc osoby czytające ten komentarz niech zamienią znak # na odpowiednio: lewy, bądź prawy nawias trójkątny.
Kot-ek, 19 listopada 2007, 12:23
Troche to przypomina szablony w c++...
Frondeus, 23 czerwca 2008, 20:50
Mi to w niczym nie przypomina szablonów, jak już to raczej wektory:D
camillos, 5 lipca 2008, 13:55
Przypomina Ci wektor i nie przypomina szablonu? std::vector z C++ to jest właśnie przykład szablonu... A jeśli mówisz o jakimś innym wektorze, to napisz coś bliżej o tym, bo szczerze mówiąc żaden inny wektor mi nie przychodzi do głowy. Pozdrawiam.
losiu99, 6 sierpnia 2008, 17:45
jesteście żałosni. spróbujcie wku na pamięc taki text a potem zaraz pisac tasoiemcowy program. dlatego bravo dla mnie i dla autora !
daniel C, 28 grudnia 2008, 17:21
przecierz to proste
sezam, 17 marca 2009, 11:45
Czy da sie jakos obejsc ograniczenie generyzmu dotyczacego operatorow? Chodzi o to, czy mozna w prosty sposob zrobic cos takiego jak w C++: template T Suma(T a, T b) { return a+b}; Z tego co wiem, kompilator najpierw sprawdza czy dla klasy T (nieznanej poki co) nie ma nigdzie zadeklarowanego operatora + wiec nie pusci programu. Inaczej niz w C++, ktory program pusci i dopiero podczas dzialania, tzn praktycznego uzycia szablonu klasy, najwyzej wyprodukuje komunikat o bledzie.
ilkus, 16 czerwca 2009, 23:43
jest tu moim zdaniem błąd mówiąc na typ niegeneryczny jako ogólny, gdyż na tym generyczny mówi się ze jest typem generycznym. Moze to pomieszac w głowie czytając inne kursy.
J, 26 kwietnia 2011, 18:17

Dodaj swój komentarz

Zasady publikacji komentarzyZasady publikacji komentarzy

Redakcja CentrumXP.pl nie odpowiada za treść komentarzy publikowanych na stronach Portalu
i zastrzega sobie prawo do usuwania wypowiedzi, które:

  • zawierają słowa wulgarne, obraźliwe, prowokujące i inne naruszające dobre obyczaje;
  • są jedynie próbami reklamowania stron internetowych (spamowanie poprzez umieszczanie linków);
  • przyczyniają się do złamania prawa bądź warunków licencyjnych oprogramowania (cracki, seriale, torrenty itp.);
  • zawierają dane osobowe, teleadresowe, adresy mailowe lub numery GG;
  • merytorycznie nie wnoszą nic do dyskusji lub nie mają związku z tematem komentowanego newsa, artykułu bądź pliku.