Pobieranie prezentacji. Proszę czekać

Pobieranie prezentacji. Proszę czekać

Waldemar Bartyna 1 Programowanie zaawansowane Delegaty.

Podobne prezentacje


Prezentacja na temat: "Waldemar Bartyna 1 Programowanie zaawansowane Delegaty."— Zapis prezentacji:

1 wbartyna@gmail.com Waldemar Bartyna 1 Programowanie zaawansowane Delegaty

2 wbartyna@gmail.com Waldemar Bartyna Plan wykładu 1.Delegaty 2.Zdarzenia 3.Metody anonimowe 4.Operator lamda 2

3 wbartyna@gmail.com Waldemar Bartyna 3 Delegaty

4 wbartyna@gmail.com Waldemar Bartyna Spojrzenie w przeszłość W Windows API często korzystano ze wskaźników do funkcji w celu tworzenia elementów zwanych funkcjami wywołań zwrotnych, albo po prostu wywołaniami zwrotnymi (ang. callback). Stosowanie tego mechanizmu pozwalało programistom na konfigurowanie wybranej funkcji tak, aby była ona w stanie wywoływać inne, dynamicznie przekazywane, funkcje. Przy pomocy tego podejścia radzono sobie z obsługą kliknięcia przycisku, poruszenia myszką, wyboru opcji z menu i innymi przykładami dwukierunkowej komunikacji między dwoma bytami programistycznymi. 4

5 wbartyna@gmail.com Waldemar Bartyna Spojrzenie w przeszłość c. d. Standardowe funkcje wywołań zwrotnych (rodem z języka C) reprezentują jedynie adres w pamięci. Wywołania zwrotne mogłyby zawierać informacje związane z bezpieczeństwem typów, takie jak ilość i typ parametrów oraz typ zwracanej wartość przez metodę, na którą wskazują. Z powodu braku tych informacji, standardowe wywołania zwrotne były często przyczyną błędów i zawieszania się aplikacji. Nie zmienia to faktu, że sam mechanizm wywołań zwrotnych jest bardzo użyteczny. 5

6 wbartyna@gmail.com Waldemar Bartyna Powrót w przyszłość Na platformie.NET, stosowanie wywołań zwrotnych jest nadal możliwe, a ich funkcjonalność została zrealizowana w bardziej bezpieczny i obiektowo zorientowany sposób. Delegat to obiekt zapewniający bezpieczeństwo typu, wskazujący na metodę (lub zbiór metody), które mogą być wywołane w późniejszym czasie. Delegat przechowuje następujące informacje:  Adres metody, którą może wywołać,  Ilość i typ argumentów metody,  Typ wartości (lub jej brak) zwracanej przez daną metodę. 6

7 wbartyna@gmail.com Waldemar Bartyna Cechy delegatów W odróżnieniu od wskaźników do funkcji w C i C++, delegaty mogą wskazywać na statyczne i instancyjne metody. Po stworzeniu delegata i dostarczeniu potrzebnych informacji, może on dynamicznie wywoływać metody, przekazywane do niego w czasie wykonania programu. Każdy delegat jest automatycznie wyposażany w możliwość wywoływania metod w sposób synchroniczny i asynchroniczny. Upraszcza to w dużym stopniu wywoływanie metod w drugoplanowym wątku, bez konieczności tworzenia i utrzymywania obiektu wątku. 7

8 wbartyna@gmail.com Waldemar Bartyna Definiowanie delegata Delegaty tworzymy za pomocą słowa kluczowego delegate. Możemy mu nadać dowolną nazwę. Definiowany delegat musi odpowiadać sygnaturze metod, które ma przechowywać. Na przykład, chcąc stworzyć delegat o nazwie BinaryOp, który może wskazywać na dowolną metodę przyjmującą dwa parametru typu int i zwracającą typ int, zapiszemy następującą definicję: 8

9 wbartyna@gmail.com Waldemar Bartyna Klasy związane z delegatami Kompilator C#, przetwarzając definicję delegata, automatycznie generuje klasę dziedziczącą po klasie System.MulticastDelegate. Klasa ta, razem z bazową klasą System.Delegate, zapewnia wymaganą infrastrukturę pozwalającą delegatom na przechowywanie listy metod do późniejszego wywołania. 9

10 wbartyna@gmail.com Waldemar Bartyna Klasy związane z delegatami c. d. Wygenerowana przez kompilator klasa posiada trzy metody:  Metoda Invoke() służy do wywoływania każdej z metod przechowywanych w delegacie w sposób synchroniczny (wywołujący musi poczekać na zakończenie się wywoływanej metody). Metoda ta jest wywoływana niejawnie.  Metody BeginInvoke() i EndInvoke() powalają na wywołanie metody w sposób asynchroniczny w osobnym wątku wykonania.  Najczęstszym powodem korzystania z wątku jest przerzucenie do niego wykonania funkcji zajmującej dużo czasu. Dzięki delegatom, mamy taką możliwość bez ręcznego tworzenia obiektu wątku. 10

11 wbartyna@gmail.com Waldemar Bartyna Jak kompilator generuje klasę delegata? Parametry i wartość zwracana przez metodę Invoke() dokładnie odpowiadają definicji delegata. Parametry metody BeginInvoko() odpowiadają parametrom delegata, Oprócz nich, metoda ta zawsze przyjmuje dwa dodatkowe parametry (AsyncCallback i object) w związku z asynchronicznym wywołaniem. Wartość zwracana przez metodę EndInvoke() odpowiada tej zdefiniowanej w delegacie. Dodatkowo przyjmuje pojedynczy parametr – obiekt klasy implementującej interfejs IAsyncResult. 11

12 wbartyna@gmail.com Waldemar Bartyna Jak kompilator generuje klasę delegata? c. d. 12 W kolejnym przykładzie, załóżmy, że chcemy zdefiniować delegat, który może przechowywać i wywoływać metody zwracające obiekt klasy System.String i przyjmujące trzy argumenty typu System.Boolean.

13 wbartyna@gmail.com Waldemar Bartyna Jak kompilator generuje klasę delegata? c. d. 2 Delegaty mogą również wskazywać na metody przyjmujące dowolną liczbę parametrów z atrybutami ref i out. Dwie pierwsze metody zostały wygenerowane zgonie z poprzednimi przykładami. Różnica polega na tym, że metoda EndInvoke() została rozszerzona o parametry z atrybutami ref i out. 13

14 wbartyna@gmail.com Waldemar Bartyna Ogólna zasada generowania klasy delegata Zasadę tą obrazuje następujący pseudo kod: 14

15 wbartyna@gmail.com Waldemar Bartyna Klasa System.Delegate 15 Klasa bazowa System.Delegate posiada, między innymi, następujące składowe.

16 wbartyna@gmail.com Waldemar Bartyna Klasa System.MulticastDelegate Każda klasa wygenerowana przez kompilator dziedziczy po klasie System.MulticastDelegate. 16

17 wbartyna@gmail.com Waldemar Bartyna Wspólne składowe delegatów W swoim kodzie, nie możemy dziedziczyć po tych dwóch klasach. Powoduje to błąd kompilacji. Jednakże, używając słowa kluczowego delegate, pośrednio tworzymy klasę dziedziczącą po System.MulticastDelegate. Kilka składowych wspólnych dla wszystkich delegatów to:  Method – Właściwość ta zwraca obiekt klasy System.Reflection.MethodInfo, która reprezentuje szczegółowe informacje o metodzie przechowywanej przez delegata.  Target – Właściwość ta zwraca informację o typie, w którym została zdefiniowana przechowywana metoda, jeżeli jest ona zdefiniowana na poziomie obiektu. W przeciwnym razie zwraca null, co oznacza, że jest to metoda statyczna. 17

18 wbartyna@gmail.com Waldemar Bartyna Wspólne składowe delegatów c. d.  Combine() – Ta statyczna metoda dodaje wskazaną metodę do listy przechowywanej przez delegata. W C# metoda ta jest wyzwalana przez użycie przeładowanego operatora +=.  GetInvocationList( ) – Metoda ta zwraca tablicę obiektów typu System.Delegate, reprezentujących poszczególne metody do wywołania.  Remove(), RemoveAll() – Te statyczne metody usuwają wskazaną metodę (lub wszystkie) z listy wywołań delegata. 18

19 wbartyna@gmail.com Waldemar Bartyna Najprostszy przykład użycia delegata 19

20 wbartyna@gmail.com Waldemar Bartyna Najprostszy przykład użycia delegata c. d. W przykładzie zdefiniowaliśmy delegata, który może wskazywać na metody przyjmujące dwa parametry liczbowe i zwracające liczbę. Nazwy metod są nieistotne. Jeżeli chcemy umieścić docelową metodę w delegacie, po prostu przekazujemy ją poprzez konstruktor. Metodę, na którą wskazuje nasz delegat wywołujemy w sposób przypominający bezpośrednie wywołanie funkcji. W rzeczywistości, wywoływana jest niejawnie metoda Invoke(). Możemy równie dobrze wywołać ją jawnie. 20

21 wbartyna@gmail.com Waldemar Bartyna Najprostszy przykład użycia delegata c. d. 2 Delegaty na platformie.NET zapewniają bezpieczeństwo typów. Dlatego też próba przekazania do delegata metody nie odpowiadającej zadanemu wzorcowi (sygnaturze metody) spowoduje wyświetlenie błędu podczas kompilacji. Załóżmy, że klasa SimpleMath posiada jeszcze jedną metodę. Próba przekazania jej do delegata spowoduje błąd w czasie kompilacji (metoda nie odpowiada sygnaturze delegata). 21

22 wbartyna@gmail.com Waldemar Bartyna Pozyskiwanie informacji o metodach Metoda wyświetlająca informacje o metodach przechowywanych w podanym delegacie. Po odpowiedniej zmianie metody main() w naszym przykładzie, otrzymamy następujący rezultat. Dlaczego? 22

23 wbartyna@gmail.com Waldemar Bartyna Pozyskiwanie informacji o metodach c. d. Po zmianie metod ze statycznych na wywoływane z poziomu instancji, nadal możemy przekazywać je do delegata. Informacje o metodzie instancyjnej zawierają informacje o typie, w którym zostały zdefiniowane (właściwość Target). 23

24 wbartyna@gmail.com Waldemar Bartyna Dodanie delegatów do klasy Car Aby zastąpić komunikację z klasą Car za pomocą interfejsów wywołań zwrotnych na delegaty należy:  Zdefiniować nowy typ delegata, który wyśle powiadomienie do wywołującego,  Zadeklarować w klasie Car zmienne odpowiednich typów delegatów,  Stworzyć funkcje pomocnicze, które pozwolą wywołującemu na przekazanie metod do zadeklarowanych zmiennych (delegatów),  Zaktualizować metodę Accelerate(), tak aby wywoływała metody na liście delegata w odpowiedniej sytuacji. 24

25 wbartyna@gmail.com Waldemar Bartyna Dodanie delegatów do klasy Car c. d. 25

26 wbartyna@gmail.com Waldemar Bartyna Dodanie delegatów do klasy Car c. d. 2 26

27 wbartyna@gmail.com Waldemar Bartyna Dodanie delegatów do klasy Car c. d. 3 27

28 wbartyna@gmail.com Waldemar Bartyna Multicasting Aby zapewnić możliwość rejestrowania wielu metod w jednej zmiennej delegata (i tym samym możliwość wywoływania wielu metod jednocześnie – ang. multicasting), należy odpowiednio zmienić implementację metod pomocniczych. Poprzez użycie przeładowanego operatora +=, wywołują one metodę Combine() dołączając wskazaną metodę do listy wywołań delegata. 28

29 wbartyna@gmail.com Waldemar Bartyna Multicasting c. d. 29

30 wbartyna@gmail.com Waldemar Bartyna Usunięcie metody z listy wywołań Aby wywołujący mógł usunąć metodę z listy wywołań, należy dostarczyć odpowiednie metody pomocnicze. Korzystają one z przeładowanego operatora -=, który powoduje niejawne wywołanie metody Remove(). 30

31 wbartyna@gmail.com Waldemar Bartyna Usunięcie metody z listy wywołań c. d. W poniższym przykładzie usunięcia metody, pamiętamy zmienną delegata, którą później przekazujemy do usunięcia. Możliwe jest również ponowne zdefiniowania delegata na bazie metody, którą chcemy usunąć z listy. Tak więc przetrzymywanie zmiennej z takim delegatem nie jest konieczne. 31

32 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład 32 Tradycyjnie zaczynamy od odpowiedniej modyfikacji klasy Car.

33 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład c. d. Do klasy Car dodajemy również definicję kolejnego typu delegata. CarMaintenanceDelegate może przechowywać i wywoływać dowolną metodę przyjmującą jako parametr obiekt klasy Car i nie zwracającą żadnej wartości. 33

34 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład c. d. 2 Dodajemy definicję klasy, przechowującej listę samochodów za pomocą kolekcji generycznej. Na kolejnym slajdzie znajduje się definicja metody tej klasy, która jako argument przyjmuje wskazany typ delegata. 34

35 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład c. d. 3 35

36 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład c. d. 4 36 Dodajemy klasę definiującą metody, które będą przechowywane i wywoływane przez delegata klasy Car.

37 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład c. d. 5 Garaż deleguje całą pracę do działu obsługi 37

38 wbartyna@gmail.com Waldemar Bartyna Bardziej złożony przykład c. d. 6 38

39 wbartyna@gmail.com Waldemar Bartyna Kowariancja delegatów Do tej pory, przykładowe delegaty zwracały proste wartości liczbowe. Mogą one również zwracać złożone klasy należące do różnych hierarchii dziedziczenia. Załóżmy, że mamy klasę Car i dziedziczącą po niej klasę SportsCar. Utwórzmy delegat, który wywołuje utworzenie obiektu. 39

40 wbartyna@gmail.com Waldemar Bartyna Kowariancja delegatów c. d. 40

41 wbartyna@gmail.com Waldemar Bartyna Kowariancja delegatów c. d. 2 41

42 wbartyna@gmail.com Waldemar Bartyna Kowariancja delegatów c. d. 3 Kowariancja pozwala na przekazywanie do delegata metod, których typ zwracanej wartości nie jest identyczny z sygnaturą delegata, ale jest potomnym w stosunku do zwracanego typu zdefiniowanego w tym delegacie. Na podobnej zasadzie działa kontrkowariancja, z tym, że dotyczy ona argumentów metod przekazywanych do delegata. 42

43 wbartyna@gmail.com Waldemar Bartyna Generyczne delegaty 43

44 wbartyna@gmail.com Waldemar Bartyna Generyczne delegaty c. d. 44

45 wbartyna@gmail.com Waldemar Bartyna 45 Zdarzenia

46 wbartyna@gmail.com Waldemar Bartyna Niedogodności związane z delegatami Delegaty są konstrukcjami umożliwiającymi dwukierunkową komunikację między obiektami w pamięci. Jednak wykorzystywanie ich w surowej postaci pociąga za sobą kilka niedogodności. Aby posłużyć się delegatem musimy:  Zdefiniować typ delegata,  Zadeklarować potrzebne zmienne tego typu,  Stworzyć własne metody pomocnicze pozwalające na rejestrowanie i wyrejestrowywanie metod z delegatów w celu zachowania hermetyzacji. W przypadku zadeklarowania zmiennej delegata jako publicznej, ryzykujemy możliwości manipulacji na liście wywołań przez potencjalnie niebezpieczny kod w obiektach korzystających z naszego delegata. 46

47 wbartyna@gmail.com Waldemar Bartyna Słowo kluczowe event Rozwiązaniem tych niedogodności jest słowo kluczowe event. Gdy kompilator napotka na to słowo, automatycznie generuje metody do rejestracji i wyrejestrowywania metod oraz zmienną do przechowywania listy tych metod. Zmienne te są zawsze deklarowane jako prywatne. W sumie, słowo kluczowe event (zdarzenie) jest po prostu syntaktycznym skrótem, który oszczędza czas programiście (podobnie jak w przypadku właściwości automatycznych). 47

48 wbartyna@gmail.com Waldemar Bartyna Definiowanie zdarzenia Definiowanie zdarzenia to dwukrokowy proces: –Najpierw definiujemy odpowiedni typ delegata, –Następnie definiujemy zdarzenie skojarzone z tym delegatem. 48

49 wbartyna@gmail.com Waldemar Bartyna „Odpalanie” zdarzeń 49

50 wbartyna@gmail.com Waldemar Bartyna Rejestracja metod obsługujących zdarzenie 50

51 wbartyna@gmail.com Waldemar Bartyna Korzystajmy z pomocy środowiska Przy dodawaniu metod do zdarzeń możemy skorzystać z pomocy środowiska. Po wpisaniu operatora +=, system pomocy podpowiada nam, jakiego rodzaju delegat jest obsługiwany przez dane zdarzenie. Po kliknięciu tabulatora, system pomocy doda odpowiedni konstruktor i teraz z kolei proponuje nam nazwę metody obsługującej dane zdarzenie. Jeżeli ponownie wciśniemy tabulator, zostanie wygenerowany szkielet metody o proponowanej nazwie. 51

52 wbartyna@gmail.com Waldemar Bartyna Wzorzec zdarzenia Zdarzenia w bibliotece klas bazowych.NET definiowane są zgodnie ze wspólnym standardem. Delegaty przez nie obsługiwane przyjmują zawsze dwa parametry:  Pierwszym jest System.Object reprezentujący referencje do obiektu, który wywołał dane zdarzenie.  Drugi dziedziczy po typie System.EventArgs i reprezentuje informacje o aktualnym zdarzeniu. 52

53 wbartyna@gmail.com Waldemar Bartyna Wzorzec zdarzenia c. d. W przypadku prostych zdarzeń można bezpośrednio przekazać obiekt klasy EventArgs. W innych przypadkach należy stworzyć własną klasę dziedziczącą po klasie EventArgs. 53

54 wbartyna@gmail.com Waldemar Bartyna Wzorzec zdarzenia c. d. 2 Obecnie, definicja naszego delegata będzie wyglądać następująco: Odpalenie zdarzenia związanego z powyższym delegatem 54

55 wbartyna@gmail.com Waldemar Bartyna Strona wywołującego I odpowiednio dopasowujemy metody obsługujące zdarzenia po stronie wywołującego. 55

56 wbartyna@gmail.com Waldemar Bartyna Generyczny delegat EventHandler Skoro tyle delegatów przyjmuje jako parametr obiekt klasy System.Object oraz potomka klasy EventArgs, możemy jeszcze bardziej uprościć nasz kod poprzez wykorzystanie generycznego delegata EventHandler, gdzie T jest niestandardową klasą dziedziczącą po EventArgs. 56

57 wbartyna@gmail.com Waldemar Bartyna Generyczny delegat EventHandler c. d. 57

58 wbartyna@gmail.com Waldemar Bartyna 58 Metody anonimowe i operator lambda

59 wbartyna@gmail.com Waldemar Bartyna Problem Metody służące do obsługi zdarzeń nie są przeważnie wykorzystywane w innym miejscu aplikacji. 59

60 wbartyna@gmail.com Waldemar Bartyna Rozwiązanie 60

61 wbartyna@gmail.com Waldemar Bartyna Metody anonimowe Możliwe jest powiązanie delegata bezpośrednio z blokiem kodu w momencie rejestracji obsługi zdarzenia. Taki blok kodu jest nazywany metodą anonimową. Składnia metody anonimowej wygląda następująco: Z metody anonimowej mamy dostęp do zewnętrznych zmiennych (oprócz zmiennych oznaczonych atrybutem ref i out. 61

62 wbartyna@gmail.com Waldemar Bartyna Konwersja grup metod Kompilator obsługuje również konwersję grup metod. Dzięki niej możemy do zdarzenia dodać od razu nazwę metody obsługującej dane zdarzenie (bez koniczności tworzenia delegata). W razie konieczności, samą nazwę metody można rzutować na odpowiedni typ delegata. 62

63 wbartyna@gmail.com Waldemar Bartyna Operator lambda Operator lamba (=>) pozwala jeszcze bardziej skrócić zapis metod anonimowych. 63

64 wbartyna@gmail.com Waldemar Bartyna Operator lambda c. d. Przed samym operatorem podajemy listę argumentów (typy są nieobowiązkowe) w nawiasach. W przypadku bezargumentowej metody wstawiamy przed operatorem same nawiasy: (() => … ). Po operatorze, umieszczamy blok instrukcji do wykonania, np.: 64

65 wbartyna@gmail.com Waldemar Bartyna 65 Dziękuję za uwagę


Pobierz ppt "Waldemar Bartyna 1 Programowanie zaawansowane Delegaty."

Podobne prezentacje


Reklamy Google