17. Typy generyczne (generics)

17. Typy generyczne (generics)

Autor: Daniel Celeda

Opublikowano: 5/30/2006, 12:00 AM

Liczba odsłon: 149351

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();
        }
    }
}

Jak wykorzystać Copilot w codziennej pracy? Kurs w przedsprzedaży
Jak wykorzystać Copilot w codziennej pracy? Kurs w przedsprzedaży

Wydarzenia