04.10 Generički delegati
Uvod: Šta su to delegati?
Delegati u C# su specijalan tip koji omogućava da se funkcije (metode) tretiraju kao objekti. Na ovaj način možemo prosleđivati funkcije kao parametre drugim funkcijama, ili im dodeljivati različite funkcije dinamički tokom izvršavanja programa.
Delegat je, u suštini, kao pokazivač na funkciju — on "drži" referencu na neku funkciju koju kasnije možemo pozvati.
Poređenje sa zadavanjem zadataka: Delegat je kao osoba kojoj možete zadati određeni zadatak (ili funkciju). Zamislite da imate prijatelja kojem možete reći šta treba da uradi. Na primer, možete ga zamoliti da pošalje poruku ili da kupi doručak. Delegat u C# radi nešto slično: on je „posrednik“ koji zna koji zadatak treba da izvrši (metod) i možete ga koristiti za pokretanje tog zadatka u kodu.
ili...
Delegat je kao daljinski upravljač: Zamislite delegat kao daljinski upravljač za TV. Daljinski upravljač ne zna koji TV kontroliše, ali zna kako da promeni kanal ili pojača ton. Kada ga povežete sa TV-om, delegat može pokrenuti određene funkcije (kao što su pojačavanje tona ili promenu kanala) na tom TV-u. U C#-u, delegat je objekat koji može pozvati neku funkciju, ali ne zna koju dok ne povežete konkretan metod.
Delegat može pokrenuti različite funkcije u zavisnosti od toga koja je funkcija u njega postavljena.
Osnovna sintaksa delegata
Definicija delegata u C#:
public delegate void MojDelegat(string poruka);
Ovaj delegat definiše tip metoda koji može primiti jedan string argument i ne vraća nikakav rezultat (tip void).
Korišćenje delegata
Evo kako možemo koristiti delegat u programu:
public delegate void MojDelegat(string poruka);
class Program
{
static void Main()
{
// Kreiramo instancu delegata i povežemo je sa metodom Pozdravi
MojDelegat delegat = Pozdravi;
// Pozivamo metod kroz delegat
delegat("Zdravo, svete!");
}
// Metod koji odgovara potpisu delegata
public static void Pozdravi(string poruka)
{
Console.WriteLine(poruka);
}
}
Objašnjenje:
- Definisali smo delegat
MojDelegat, koji prima jedanstringparametar i ne vraća ništa. - Kreirali smo instancu delegata i povezali je sa metodom
Pozdravi, koji takođe prima jedanstringparametar i ne vraća ništa. - Poziv delegata je zapravo poziv metode
Pozdraviputem delegata.
Pojednostavljeno objašnjenje:
-
Delegat je kao kutija: U tu "kutiju" stavljamo funkciju. Kada pozovemo delegat, zapravo otvaramo tu kutiju i pokrećemo funkciju koju smo prethodno stavili unutra.
-
Zašto koristiti delegat?: Možemo promeniti šta je u "kutiji" bez potrebe da menjamo ostatak koda. Tako možemo izabrati koju funkciju ćemo pokrenuti u različitim situacijama. Na primer, možemo staviti različite funkcije u delegat i pozvati ih u zavisnosti od situacije.
Delegati su veoma korisni kada želimo da koristimo isti delegat za pozivanje različitih metoda. Time postižemo veću fleksibilnost u kodu jer jedan delegat može referencirati različite funkcije koje obavljaju različite poslove, ali imaju isti potpis (iste parametre i povratni tip).
Primer 2:
Zamislimo da želimo da kreiramo delegat koji može pozvati različite metode za različite vrste obrade teksta: da prikaže tekst u originalnom obliku, da ga prikaže velikim slovima ili malim slovima.
using System;
// Definišemo delegata koji prima string i ne vraća ništa (void)
public delegate void ObradaTekstaDelegat(string tekst);
class Program
{
static void Main()
{
// Kreiramo delegat i dodeljujemo mu metod koji prikazuje tekst u originalnom obliku
ObradaTekstaDelegat obrada = PrikaziOriginalno;
// Pozivanje delegata - prikazuje tekst u originalnom obliku
obrada("Delegati su korisni!"); // Ispisuje: Delegati su korisni!
// Menjamo delegat da pokazuje na metod koji prikazuje tekst velikim slovima
obrada = PrikaziVelikaSlova;
obrada("Delegati su korisni!"); // Ispisuje: DELEGATI SU KORISNI!
// Menjamo delegat da pokazuje na metod koji prikazuje tekst malim slovima
obrada = PrikaziMalaSlova;
obrada("Delegati su korisni!"); // Ispisuje: delegati su korisni!
}
// Metod koji prikazuje tekst u originalnom obliku
public static void PrikaziOriginalno(string tekst)
{
Console.WriteLine(tekst);
}
// Metod koji prikazuje tekst velikim slovima
public static void PrikaziVelikaSlova(string tekst)
{
Console.WriteLine(tekst.ToUpper());
}
// Metod koji prikazuje tekst malim slovima
public static void PrikaziMalaSlova(string tekst)
{
Console.WriteLine(tekst.ToLower());
}
}
Objašnjenje:
- Delegat
ObradaTekstaDelegatje definisan tako da primastringi ne vraća ništa (void). - Delegat može referencirati bilo koju funkciju koja prima
stringkao parametar i ne vraća vrednost. - U glavnom programu, kreiramo instancu delegata i prvo ga povežemo sa metodom
PrikaziOriginalnokoji ispisuje tekst onako kako je prosleđen. - Nakon toga, menjamo delegat tako da pokazuje na metod
PrikaziVelikaSlova, koji ispisuje tekst velikim slovima. - Zatim delegat povezujemo sa metodom
PrikaziMalaSlova, koji ispisuje tekst malim slovima.
U ovom primeru, isti delegat koristi se za pozivanje različitih metoda u zavisnosti od situacije, a svi ti metodi imaju isti potpis.
A sada da proširimo priču: Šta su to GENERIČKI DELEGATI?
Generički delegati omogućavaju definisanje delegata koji mogu raditi sa različitim tipovima podataka.
Ključni pojmovi koje bi trebalo znati:
- Delegat: Tip podataka koji može da referencira metode sa specifičnim potpisom.
- Generički delegat: Delegat koji koristi generičke tipove i može se koristiti sa različitim tipovima podataka.
Sintaksa definisanja generičkog delegata:
public delegate T Operation<T>(T a, T b);
Operation<T>je generički delegat koji može referencirati metode koje uzimaju dva parametra tipaTi vraćaju rezultat tipaT.
Primer upotrebe generičkog delegata:
-
Kreiranje delegata i metode:
public class Program
{
public static void Main(string[] args)
{
Operation<int> add = Add;
int result = add(5, 3);
Console.WriteLine(result); // Output: 8
}
public static int Add(int x, int y)
{
return x + y;
}
}
U ovom primeru, generički delegat Operation<int> referencira metodu Add koja sabira dva cela broja.
2. Korišćenje sa različitim tipovima podataka:
public class Program
{
public static void Main(string[] args)
{
Operation<int> addIntegers = Add;
Operation<string> concatenateStrings = Concatenate;
Console.WriteLine(addIntegers(10, 20)); // Output: 30
Console.WriteLine(concatenateStrings("Hello", "World")); // Output: HelloWorld
}
public static int Add(int x, int y)
{
return x + y;
}
public static string Concatenate(string a, string b)
{
return a + b;
}
}
Ovde se generički delegat Operation<T> koristi sa različitim tipovima podataka (int i string).
Korisni generički delegati koji dolaze ugrađeni u C#:
- Func<T, TResult>: Delegat koji uzima jedan ili više parametara tipa
Ti vraća rezultat tipaTResult. - Action<T>: Delegat koji uzima jedan ili više parametara tipa
Ti ne vraća vrednost (void). - Predicate<T>: Delegat koji uzima jedan parametar tipa
Ti vraćaboolvrednost.
Primer korišćenja Func i Action delegata:
public class Program
{
public static void Main(string[] args)
{
Func<int, int, int> multiply = Multiply;
Action<string> print = PrintMessage;
Console.WriteLine(multiply(3, 4)); // Output: 12
print("Hello, World!"); // Output: Hello, World!
}
public static int Multiply(int x, int y)
{
return x * y;
}
public static void PrintMessage(string message)
{
Console.WriteLine(message);
}
}
Zadaci za učenike:
- Implementacija generičkog delegata: Definisati generički delegat koji radi sa listama i implementirati metodu koja koristi taj delegat za filtriranje elemenata liste.
- Upotrebiti
Funcdelegat: Napisati program koji koristiFuncdelegat za različite matematičke operacije (sabiranje, oduzimanje, množenje, deljenje).
- Koje su prednosti korišćenja generičkih delegata u odnosu na obične delegate?
- Kada bi bilo korisno koristiti
FunciActiondelegate? - Kako bi se generički delegati mogli koristiti u stvarnim aplikacijama?