21.09(1) Ponavljanje: Generičke klase, izvedene generičke klase, generičke metode
Pod pojmom generičko programiranje podrazumeva se izrada programskog koda koji se u nepromenjenom obliku može primeniti na različite tipove podataka.
U C#-u možemo da, između ostalog, imamo generičke klase i metode, tj klase i metode koji nisu napravljeni za neki konkretan tip ali mogu da se koriste sa bilo kojim tipom podataka.
Generički tipovi se deklarišu šiljatim zagradama < > iza kojih se navodi ime tipa.
Recimo da definišemo klasu ili metodu sa <T> i unutar te klase radimo operacije sa T. Posle prosledimo ceo broj tako što pišemo <int> - tada će T koje se nalazi unutar klase ili metode da se promeni u int prilikom kompajliranja.
(Praksa je da se između zagrada za tip koristi slovo T ukoliko se radi sa jednim parametrom ili da se koristi slovo T kao predznak - poput TKey, TValue ukoliko se deklariše više parametara. )
Primer: Generička klasa
using System;
class Genericka<T>
{
private T generickaPromenjiva;
public Genericka(T generickaVrednost)
{
this. generickaPromenjiva = generickaVrednost;
}
public void Prikaz()
{
Console.WriteLine(this.generickaPromenjiva);
}
}
class Test
{
static void Main(string[] args)
{
Genericka<int> g = new Genericka<int>(5);
Genericka<string> g1 = new Genericka<string>("tekstualna poruka");
g.Prikaz();
g1.Prikaz();
}
}
U ovom primeru je definisana generička klasa - class Genericka<T>. Unutar klase smo tretirali T kao normalne podatke i deklarisali promenljivu tipa T - private T generickaPromenjiva; .
U konstruktoru se takođe koristi promenljiva tipa T - public Genericka(T generickaVrednost). Zapamtite da će se odluka koji će tip podataka biti to T vršiti tek prilikom kreitanja objekata klase.
Genericka<int> g = new Genericka<int>(5); - ovde je tip od T postavljen da budu celi brojevi. To znači da će unutar definicije klase T biti zamenjeno sa int.
Genericka<string> g1 = new Genericka<string>("tekstualna poruka"); - u objektu g1, T je string. To znači da će T da postane string prilikom definisanja klase.
Plastično objašnjeno na ovom primeru:
Nakon izvršavanja Genericka<int> g = new Genericka<int>(5);, generička klasa će biti ovakva:
class Genericka
{
private int generickaPromenjiva;
public Genericka( int generickaVrednost)
{
this. generickaPromenjiva = generickaVrednost;
}
public void Prikaz()
{
Console.WriteLine(this.generickaPromenjiva);
}
}
Nakon izvršavanja Genericka<string> g1 = new Genericka<string>("tekstualna poruka");, generička klasa će biti ovakva:
class Genericka
{
private string generickaPromenjiva;
public Genericka(string generickaVrednost)
{
this. generickaPromenjiva = generickaVrednost;
}
public void Prikaz()
{
Console.WriteLine(this.generickaPromenjiva);
}
}
Ograničenja:
U prethodnom primeru smo koristili parametar tipa kao nešto što nam čuva mesto gde će kasnije da se postavi neki konkretan tip podataka. U C#-u možemo takođe i da ograničimo koji sve tip podataka može da se koristi, korišćenjem ključne reči where.
Na primer, ako deklarišemo klasu kao:
class NazivKlase<T> where T: class
u tom slučaju, T može da bude samo referentni tip (klasa, string i slično). Ako pokušamo nešto što nije referentni tip dobićemo grešku.
Tipovi ograničenja su dati u nastavku:
|
Ograničenje: |
Opis: |
|---|---|
|
class |
Mora biti referentni tip |
|
struct |
Mora biti vrednosni tip |
|
new() |
Mora da ima javni (public) konstruktor bez parametara. |
|
BaseClassName |
Mora da je izvedena iz klase BaseClassName. |
|
InterfaceName |
Mora da implementira interfejs InterfaceName. |
|
U |
Mora da bude ili da je izvedena iz argumenata koji su dati za U. |
Primer:
using System;
class Genericka<T> where T: class { public T generickaPromenjiva { get; set;} } class Test { static void Main(string[] args) { Genericka<int> g = new Genericka<int>();
g.generickaPromenjiva = 15;
Console.WriteLine(g.generickaPromenjiva); } }
U ovom primeru je postavljeno ograničenje da se umesto T može postavljati samo referentni tip podataka jer je napisano where T: class. Nakon toga je pokušano da se napravi objekat sa korišćenjem celog broja umesto T. Pošto je int vrednosni tip podataka, dobijamo grešku prilikom kompajliranja
… error CS0452: The type `int' must be a reference type in order to use it as type parameter `T' in the generic type or method `Genericka<T>' …
Međutim ...
Ako pokušamo sa referentnim tipom:
using System;
class Genericka<T> where T: class { public T generickaPromenjiva { get; set;} } class Test { static void Main(string[] args) { Genericka<string> g = new Genericka<string>();
g.generickaPromenjiva = "poruka u stringu";
Console.WriteLine(g.generickaPromenjiva); } }
U ovom primeru je pokušano sa stringom, koji JESTE referentni tip, i stoga je kod uspešno kompajliran.
Napomena: može se koristiti više ograničenja, po potrebi.
Izvedene generičke klase:
Primer:
using System;
class Genericka<T>
{
public T generickaPromenjiva { get; set; }
}
class Izvedena<T>: Genericka<T>
{
}
class Test
{
static void Main(string[] args)
{
Izvedena<string> s = new Izvedena<string>();
}
}
Generičke metode:
Slično kao sa generičkim klasama, možemo da kreiramo i generičke metode:
Primer:
using System;
class Test
{
static void PRIKAZ<T>(T poruka)
{
Console.WriteLine(poruka);
}
static void Main(string[] args)
{
PRIKAZ(" Auuuuu !!! ");
PRIKAZ(10);
}
}
U ovom primeru imamo generički metod PRIKAZ kojem je kao parametar tipa u špicastim zagradama napisano T.
Prvo smo metodi kao parametar prosledili string, a posle toga ceo broj – i sve treba da radi ok.