Delegaty to referencyjny typ danych, który przechowuje referencje do metody. Referencja ta może być zmieniana w
trakcie wykonywania programu.
Delegaty są przede wszystkim wykorzystywane do implementacji zdarzeń oraz wywołań zwrotnych
metod(call-back). Czym są wywołania zwrotne? Programista rejestruje metodę do
późniejszego wywołania, natomiast biblioteka wywołuje ją w stosownym dla siebie czasie. Wszystkie delegaty
niejawnie dziedziczą z klasy System.Delegate.
Deklarowanie delegatów
Deklaracja delegatu określa metody, które mogą być wywołane za jego pomocą. Delegat może się odnosić do metody,
która ma taką samą sygnaturę jak delegat.
Definicja:
public delegate int MyDelegate (string s);
Powyższy delegat może być wykorzystany do odniesienia się do jakiejkolwiek metody, która ma jeden parametr typu
string oraz zwraca zmienną całkowitą typu int.
Jeżeli delegat został już zadeklarowany, należy utworzyć obiekt delegatu korzystając ze słowa kluczowego
new oraz powiązać go z konkretną metodą. Podczas tworzenia delegata, argument
przekazywany do tego wyrażenia jest podobny do wywołania metody, z tym, że nie podaje się argumentów metody.
Przykład:
public delegate void PrintMessage(string s);
…
PrintMessage1=new PrintMessage(WriteToScreen);
PrintMessage2=new PrintMessage(WriteToFile);
Poniższy przykład pokazuje deklaracje, utworzenie instancji oraz użycie delegata, który może mieć referencje
do metody przyjmującej liczbę całkowitą oraz zwracającej liczbę całkowitą:
using System;
namespace Delegaty
{
delegate int ChangeNumber(int i);
class Program
{
static int number = 5;
public static int AddNumber(int i)
{
number += i;
return number;
}
public static int MultiplyNumber(int i)
{
number *= i;
return number;
}
public static int GetNumber()
{
return number;
}
static void Main(string[] args)
{
// tworzenie instancji delegatów
ChangeNumber cn1 = new ChangeNumber(AddNumber);
ChangeNumber cn2 = new ChangeNumber(MultiplyNumber);
// wywoływanie metod używajac delegatów
cn1(5);
Console.WriteLine("Wartość liczby: {0}", GetNumber());
cn2(10);
Console.WriteLine("Wartość liczby: {0}", GetNumber());
Console.ReadKey();
// Wynik działania programu
// Wartosc liczby: 10
// Wartosc liczby: 100
}
}
}
Delegaty złożone
Obiekty delegata mogą być łączone za pomocą operatora (+). Delegat złożony
wywołuje dwa delagaty tak jakby były złączone. Jedynie delegaty tego samego typu mogą być ze sobą złożone.
Operator (-) może być użyty do usunięcia danego delegatu z delagata złożonego.
Korzystając z tej właściwości delegatów można utworzyć listę delegatów, które zostaną wywołane, w momencie
wywołania delegatu złożonego. Operacja taka to tzw. multicasting. Poniższy
program pokazuje przykład wykorzystania takiej operacji:
Przykład:
using System;
namespace Delegaty
{
delegate int ChangeNumber(int i);
class Program
{
static int number = 5;
public static int AddNumber(int i)
{
number += i;
return number;
}
public static int MultiplyNumber(int i)
{
number *= i;
return number;
}
public static int GetNumber()
{
return number;
}
static void Main(string[] args)
{
// tworznie instancji delegata złożonego
ChangeNumber cn;
// tworzenie instancji delegatów
ChangeNumber cn1 = new ChangeNumber(AddNumber);
ChangeNumber cn2 = new ChangeNumber(MultiplyNumber);
cn = cn1;
cn += cn2;
// Wywołanie delegata złożonego
cn(5);
Console.WriteLine("Wartość liczby: {0}", GetNumber());
Console.ReadKey();
// Wynik działania programu
// Wartosc liczby: 50
}
}
}
Przykład użycia delagatów
Poniższy przykład pokazuje zastosowania delegatów. Delegat PrintMessage może
być wykorzystany jako referencja do metod, które przyjmują parametr typu string
oraz nie zwracając niczego. Typ metody: void.
Delegat zostanie użyty do wywołania dwóch metod, pierwsza z nich wypisuje informacje w konsoli, druga w pliku
tekstowym:
using System;
using System.IO;
namespace DelegatyPrzyklad
{
class Program
{
static FileStream fs;
static StreamWriter sw;
// deklaracja delegatu
public delegate void PrintMessage(string s);
// Metoda wypisująca wiadomość w konsoli
public static void WriteToConsole(string s)
{
Console.WriteLine("Wiadomość: {0}", s);
}
public static void WriteToFile(string s)
{
// FileMode.Append - jeżeli uruchomicie program kilka razy za każdym razem do
// pliku tekstowego zostanie dodana kolejna linika tekstu
fs = new FileStream("c:\\wiadomosc.txt", FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs);
// Zapisujemy dane do pliku
sw.WriteLine(s);
// Czyszczenie naszego bufora
sw.Flush();
// Zamykamy obydwa strumienie
sw.Close();
fs.Close();
}
// Metoda jako parametr przyjmuje delagat
// Oraz wywołuje dany delegat ze stosowną wiadomością
public static void SendString(PrintMessage pm)
{
pm("Witaj Świecie");
}
static void Main(string[] args)
{
PrintMessage pm1 = new PrintMessage(WriteToConsole);
PrintMessage pm2 = new PrintMessage(WriteToFile);
SendString(pm1);
SendString(pm2);
Console.ReadKey();
// Wynik działania programu
// Wiadomosc: Witaj Swiecie
// Oraz proszę spojrzeć na dysk C, został utworzony nowy plik
// Wewnątrz tekst: Witaj Świecie
}
}
}