Delegaty ogólnie:
A więc co to jest delegat (ang. delegate). Jest to obiekt typu referencyjnego, który wskazuje na metodę lub metody o określonej sygnaturze. Delegaty są mniej więcej podobne do wskaźników funkcji w języku C ++, jednak posiadają większe możliwości. Typowa sytuacja użycia delegatów ma miejsce, kiedy kod, który ma wykonać pewne operacje, nie zna ich dokładnej treści.
Dla przykładu klasa Thread może wykonać zadanie w nowym wątku po starcie, ponieważ przekazałeś jej w konstruktorze instancję delegata typu ThreadStart lub ParameterizedThredStart.
Aby delegaty mogły cokolwiek zrobić:
- musi zostać zadeklarowany typ delegatowy
- musi istnieć metoda zawierająca kod do wykonania
- musi zostać utworzona instancja delegata
- instancja delegata musi zostać wywołana
Deklaracja typu delegatowego:
[modifiers] delegate result-type identifier ([formal-parameters]);
np.
public delegate void StrigProcessor(string input)
Gdzie:
- modifiers (optional)
- Możemy tu użyć słów kluczowych jak we wszystkich innych typach tj. public, protected, internal itd.
- delegate
- Słowo kluczowe delegate oznacza, że tworzymy delegat.
- result-type
- Typ zwracanych, który musi być zgodny ze typem zwracanym metody do której referujemy.
- identifier
- Nazwa delegata
- formal-parameters (optional)
- Jest to lista parametrów, jakie posiadać musi metoda do, której prowadzi referencja
Powyższa deklaracja mówi, że jeżeli chcemy stworzyć instancję delegata StringProcessor, będziemy potrzebować metody, która posiada typ zwracany void, oraz przyjmuje jeden parametr typu string.
Wyszukiwanie odpowiedniej metody dla instancji delegata:
Kolejnym krokiem jest znalezienie lub napisanie metody która spełnia wszystkie wymagane warunki, czyli zgadzają się parametry oraz typ zwracany – tak jak ma to miejsce w przypadku wywołania zwykłej metody. Dla przykładu dla powyższego typu delegatowego będzie pasowała tylko jedna z poniższych metod:
void PrintString(string s) void PrintInteger(int i) void PrintTwoStrings(string x, string y) int GetStringLength(string s) void PrintObject(object x)
Jedyną pasującą metodą jest metoda pierwsza – ponieważ tylko w tym przypadku zgadza się zarówno typ zwracany jak i parametry. Co prawda od wersji C# 4.0 istnieją jeszcze inne możliwości, jednak tym zajmiemy się w innym czasie.
Tworzenie instancji delegata:
A więc mamy juz typ delegatowy oraz odpowiadającą mu metodę z własciwą sygnaturą. Możemy teraz przystąpić do stworzenia instancji delegata, tak żeby wybrana przez nas metoda została wykonana.
StringProcessor proc1 = new StringProcessor(PrintString)
Wywołanie instancji delegata:
Wywołanie delegata jest bardzo proste. Wywołuje się do tak jak zwykłą funkcję.
proc1("Some string");
Przykładowy kod:
using System; namespace SimpleDelegateBlog { class Program { public delegate void StringProcessor(string input); static void Main(string[] args) { StringProcessor proc1 = new StringProcessor(PrintString); proc1("Some string"); } static void PrintString(string s) { Console.WriteLine(s); } } }
Na wyjściu w konsoli zostanie wyświetlony napis: Some string
Delegaty złożone:
Do tej pory omówiliśmy delegaty posiadające jedną akcję. Bardzo ważną i przydatną funkcją jest możliwość tworzenia grup delegatów. Utworzoną grupę nazywamy delegatem złożonym. Łączyć ze sobą można jedynie delegaty tego samego typu. Do dodawania delagata do grupy możemy posłużyć się operatorem „+” lub „+=”. Podobnie dla usuwania delegatów z delegata złożonego posłużymy się operatorami „-” lub „-=”. Łączenie i usuwanie delegatów jest szczególnie przydatne w zdarzeniach, gdzie możemy chcieć wykonać wiele akcji.
Poniżej prosty kod obrazujący jak wygląda łączenie delegatów:
using System; namespace SimpleDelegateBlog { class Program { public delegate void StringProcessor(string input); static void Main(string[] args) { // Stworzenie delegata złozonego StringProcessor proc; // Stowrzenie instancji naszych poszczególnych delegatów StringProcessor proc1 = new StringProcessor(PrintString); StringProcessor proc2 = new StringProcessor(PrintString2); // Stworzenie instancji delegata złozonego proc = proc1; proc += proc2; // Wywołanie delegata złozonego proc("Some string"); } static void PrintString(string s) { Console.WriteLine(s + " written by PrintString method"); } static void PrintString2(string s) { Console.WriteLine(s + " written by PrintString2 method"); } } }
Na wyjściu w konsoli dostaniemy:
Some string written by PrintString method
Some string written by PrintString2 method
Więcej o delegatach w połączeniu z wyrażeniami lambda możecie się dowiedzieć w kolejnym moim poście – „Wyrażenia lambda – delegaty cz.2”