Delegaty i zdarzenia

Stronę tą wyświetlono już: 281 razy

Wstęp

Wyobraźmy sobie taką oto sytuację, że utworzony został pewien zbiór obiektów geometrycznych, z których każdy może się przemieszczać w pewnej funkcji czasu i gdy piszę, że może to znaczy że obiekt ten nie musi koniecznie się przemieszczać. A więc, jeżeli przemieszczenie obiektu jest zerowe to obiekt się nie przemieszcza, a jeżeli jest różne od zera to się przemieszcza. Przemieszczenie obiektu nazwijmy sobie zdarzeniem, w reakcji na to zdarzenie obiekt wywołuje pewien zbiór funkcji, tak zwanych delegatów, które mają za zadanie poinformować wszystkie inne obiekty o tym, że ten konkretny obiekt się przemieścił. W odpowiedzi na to każdy z pozostałych obiektów sprawdza, czy nie nastąpiła jego kolizja z obiektem wysyłającym zgłoszenie zdarzenia.

Najczęściej zdarzenia będą spotykane przy tworzeniu programów okienkowych w C#, np zdarzenie Click dla przycisku.

Delegaty i zdarzenia

W poniższym przykładzie wykorzystałem wcześniej już opisywaną na stronie Programowanie → Podstawy C# → Obsługa operatorów struktur i klas definicję klasy Point2D. Poniżej zamieszczam przykład zastosowania delegacji i zdarzeń:

Listing 1
  1. public delegate void collision(circle c); // tworzenie typu delegata
  2. public class circle : Point2D
  3. {
  4. protected uint ray;
  5. public event collision col; // tworzenie zdarzenia, które będzie wywoływane, gdy obiekt będzie się przemieszczał
  6. public uint Ray
  7. {
  8. get { return ray; }
  9. set { ray = value; }
  10. }
  11. public circle()
  12. {
  13. ray = 0;
  14. col = null;
  15. }
  16. public circle(uint ray, double x, double y)
  17. : base(x, y)
  18. {
  19. this.ray = ray;
  20. col = null;
  21. }
  22. public void move(double dx, double dy)
  23. {
  24. X += dx;
  25. Y += dy;
  26. if (dx != 0 || dy != 0)
  27. {
  28. if (col != null)
  29. {
  30. col(this); // tutaj wywoływane będą wszystkie funkcje przypisane do zdarzenia
  31. }
  32. }
  33. }
  34. public void collision_reaction(circle c) // ta metoda będzie wykorzystywana do generowania reakcji na zdarzenie
  35. {
  36. if (Math.Sqrt((c.X - X) * (c.X - X) + (c.Y - Y) * (c.Y - Y)) <= c.Ray + ray)
  37. {
  38. Console.WriteLine("okrąg o współrzędnych: x = " + c.X + "; y = " + c.Y + "; i promieniu r = " + c.Ray);
  39. Console.WriteLine("koliduje z okrągiem o współrzędnych: x = " + X + "; y = " + Y + "; i promieniu r = " + Ray);
  40. }
  41. else
  42. {
  43. Console.WriteLine("brak zderzenia");
  44. }
  45. }
  46. }

W powyższym kodzie utworzony został typ delegacji collision (kolizja), który określa jaki typ metod może on przechowywać, ponieważ w przypadku, gdy dany delegat zwraca typ void to taki delegat przechowuje listę metod, które w reakcji na jego wywołanie kolejno będą wywoływane. Utworzenie zdarzenia ma miejsce wewnątrz klasy i jest ono ściśle powiązane z utworzeniem obiektu delegacji z wykorzystaniem słowa kluczowego event (zdarzenie). Klasa circle będzie wywoływała zdarzenie col, gdy dojdzie do przemieszczenia tegoż obiektu w celu obsłużenia wykrycia i reakcji na ewentualną kolizję.

A oto kod, który wywołuje odpowiedź na zdarzenie col:

Listing 2
  1. var c1 = new circle(10, 100, 0);
  2. var c2 = new circle(10, 10, 0);
  3. c1.col += c2.collision_reaction; // dodanie zdarzenia do obiektu c1 jako metody z obiektu c2
  4. c2.col += c1.collision_reaction; // to samo, tylko że na odwrót
  5. c1.move(-93, 0); // przemieszczenie obiektu wywoła pierwsze zdarzenie mówiące o zderzeniu c1 z c2
  6. c2.move(100,200); // przemieszczenie obiektu wywoła drugie zdarzenie mówiące, że obiekty się nie zderzyły
  7. Console.ReadLine();

Wynik działania powyższego kodu jest następujący:

okrąg o współrzędnych: x = 7; y = 0; i promieniu r = 10
koliduje z okrągiem o współrzędnych: x = 10; y = 0; i promieniu r = 10
brak zderzenia

Możliwe jest również usunięcie danej metody z listy zdarzeń za pomocą operatora -=. Dodatkowo można utworzyć delegację, która zwraca jakąś wartość, w takim przypadku obiekt takiego delegata nie może przyjmować listy metod a jedynie jedną metodę.

Komentarze