Nie widzę zalet używania wydarzeń nad delegatami, poza byciem cukrem syntaktycznym. Może nie rozumiem, ale wygląda na to, że wydarzenie jest tylko miejscem zastępczym dla delegata.
Czy mógłbyś wyjaśnić mi różnice i kiedy których użyć? Jakie są zalety i wady? Nasz kod jest mocno zakorzeniony w zdarzeniach i chcę dotrzeć do sedna tego.
Kiedy używałbyś delegatów do wydarzeń i odwrotnie? Proszę podać swoje rzeczywiste doświadczenia z obydwoma, powiedzmy w kodzie produkcji.
Odpowiedzi:
Z technicznego punktu widzenia inne odpowiedzi dotyczyły różnic.
Z punktu widzenia semantyki zdarzenia to akcje wywoływane przez obiekt, gdy spełnione są określone warunki. Na przykład moja klasa Stock ma właściwość o nazwie Limit i wywołuje zdarzenie, gdy ceny akcji osiągną Limit. To powiadomienie odbywa się za pośrednictwem wydarzenia. Klasa właścicieli nie jest zainteresowana tym, czy ktoś naprawdę obchodzi to wydarzenie i się na nie zapisuje.
Delegat to bardziej ogólny termin opisujący konstrukcję podobną do wskaźnika w terminach C / C ++. Wszyscy delegaci w .Net są delegatami multiemisji. Z punktu widzenia semantyki są one zwykle używane jako rodzaj danych wejściowych. W szczególności są doskonałym sposobem na wdrożenie wzorca strategii . Na przykład, jeśli chcę posortować listę obiektów, mogę dostarczyć metodzie strategię komparatora, aby poinformować implementację, jak porównać dwa obiekty.
Użyłem tych dwóch metod w kodzie produkcyjnym. Mnóstwo moich obiektów danych powiadamia o spełnieniu określonych właściwości. Najbardziej podstawowy przykład, gdy zmienia się właściwość, wywoływane jest zdarzenie PropertyChanged (zobacz interfejs INotifyPropertyChanged). Użyłem delegatów w kodzie, aby zapewnić różne strategie przekształcania niektórych obiektów w ciąg. Ten konkretny przykład był gloryfikowaną listą implementacji ToString () dla określonego typu obiektu w celu wyświetlenia go użytkownikom.
źródło
Słowo kluczowe
event
jest modyfikatorem zakresu dla delegatów multiemisji. Praktyczne różnice między tym a zwykłym deklarowaniem delegata multiemisji są następujące:event
w interfejsie.public event
.).Interesujące jest zastosowanie
+
i-
do delegatów multiemisji, a to jest podstawa składni+=
i-=
do przypisywania delegatów do zdarzeń. Te trzy fragmenty są równoważne:Próbka druga, ilustrująca przypisanie bezpośrednie i przypisanie kombinowane.
Próbka trzecia: bardziej znana składnia. Prawdopodobnie znasz przypisanie wartości null do usuwania wszystkich programów obsługi.
Podobnie jak właściwości, zdarzenia mają pełną składnię, której nikt nigdy nie używa. To:
... robi dokładnie to samo:
Metody add i remove są bardziej widoczne w raczej sztywnej składni używanej przez VB.NET (brak przeciążeń operatorów).
źródło
Wydarzenia to cukier syntaktyczny. Są pyszne. Kiedy widzę wydarzenie, wiem, co robić. Kiedy widzę delegata, nie jestem taki pewien.
Połączenie wydarzeń z interfejsami (więcej cukru) tworzy przepyszną przekąskę. Delegaci i czyste wirtualne klasy abstrakcyjne są znacznie mniej apetyczne.
źródło
Zdarzenia są oznaczone jako takie w metadanych. Dzięki temu elementy takie jak Windows Forms lub projektanci ASP.NET mogą odróżniać zdarzenia od zwykłych właściwości typu delegata i zapewniać im odpowiednią obsługę (w szczególności pokazując je na karcie Zdarzenia w oknie Właściwości).
Inną różnicą w stosunku do właściwości typu delegata jest to, że użytkownicy mogą tylko dodawać i usuwać programy obsługi zdarzeń, podczas gdy w przypadku właściwości typu delegata mogą ustawiać wartość:
Pomaga to wyodrębnić subskrybentów zdarzeń: mogę dodać moją procedurę obsługi do zdarzenia i możesz dodać swoją procedurę obsługi do tego samego zdarzenia i nie zastąpisz jej przypadkowo.
źródło
Chociaż zdarzenia są zwykle implementowane z delegatami multiemisji, nie ma wymogu, aby były używane w taki sposób. Jeśli klasa ujawnia zdarzenie, oznacza to, że klasa ujawnia dwie metody. Ich znaczenie to w istocie:
Najczęstszym sposobem obsługi zdarzenia przez klasę jest zdefiniowanie delegata multiemisji i dodanie / usunięcie delegatów, którzy zostaną przekazani do powyższych metod, ale nie ma wymogu, aby działały w ten sposób. Niestety, architektura zdarzenia nie robi pewnych rzeczy, które uczyniłyby alternatywne podejścia znacznie czystszymi (np. Metoda subskrypcji zwróciłaby MethodInvoker, który byłby zachowany przez subskrybenta; aby anulować subskrypcję zdarzenia, po prostu wywołaj zwróconą metodę), więc delegaci multiemisji są zdecydowanie najbardziej powszechnym podejściem.
źródło
aby zrozumieć różnice, spójrz na te 2 przykłady
Przykład z delegatami (w tym przypadku akcja jest rodzajem delegata, który nie zwraca wartości)
aby użyć delegata, powinieneś zrobić coś takiego
ten kod działa dobrze, ale możesz mieć słabe punkty.
Na przykład, jeśli to napiszę
z ostatnim wierszem kodu nadpisałem poprzednie zachowania tylko z brakującym jednym
+
(użyłem+
zamiast+=
)Innym słabym punktem jest to, że każda klasa, która używa twojej
Animal
klasy, może podbićRaiseEvent
po prostu ją wywołującanimal.RaiseEvent()
.Aby uniknąć tych słabych punktów, możesz użyć
events
w języku C #.Twoja klasa zwierząt zmieni się w ten sposób
do wywoływania wydarzeń
Różnice:
notatki
EventHandler jest zadeklarowany jako następujący delegat:
pobiera nadawcę (typu Object) i argumenty zdarzenia. Nadawca ma wartość null, jeśli pochodzi z metod statycznych.
Możesz użyć również
EventHAndler
zamiast tego przykładu, który używaEventHandler<ArgsSpecial>
patrz tutaj dla dokumentacji o EventHandler
źródło
Projektując własne API, definiuję delegatów, które są przekazywane jako parametry do metod lub do konstruktorów klas:
Predicate
iAction
są przekazywane do klas kolekcji generycznych .Net)Te delegaty na ogół nie są opcjonalne w czasie wykonywania (tj. Nie mogą być
null
).Zwykle nie używam wydarzeń; ale tam, gdzie używam zdarzeń, używam ich do opcjonalnego sygnalizowania zdarzeń do zera, jednego lub większej liczby klientów, którzy mogą być zainteresowani, tj. kiedy ma sens, aby klasa (np.
System.Windows.Form
klasa) istniała i była uruchamiana niezależnie od tego, czy klient ma dodał obsługę zdarzenia do swojego zdarzenia (np. istnieje zdarzenie „mouse down” formularza, ale jest opcjonalne, czy jakikolwiek klient zewnętrzny jest zainteresowany instalacją obsługi zdarzenia do tego zdarzenia).źródło
Chociaż nie mam ku temu technicznych powodów, używam zdarzeń w kodzie w stylu interfejsu użytkownika, innymi słowy, na wyższych poziomach kodu i używam delegatów do logiki, która leży głębiej w kodzie. Jak mówię, możesz użyć jednego i drugiego, ale uważam, że ten wzorzec użycia jest logiczny, jeśli nic innego, pomaga udokumentować typy wywołań zwrotnych i ich hierarchię.
Edycja: Myślę, że różnica we wzorcach użytkowania byłaby taka, że uważam, że ignorowanie zdarzeń jest całkowicie dopuszczalne, są to hooki / stuby, jeśli chcesz wiedzieć o zdarzeniu, posłuchaj ich, jeśli cię to nie obchodzi wydarzenie po prostu je zignoruj. Dlatego używam ich w interfejsie użytkownika, w stylu zdarzeń Javascript / Browser. Jednak kiedy mam delegata, NAPRAWDĘ oczekuję, że ktoś obsłuży zadanie delegata i wyrzuci wyjątek, jeśli nie zostanie obsłużony.
źródło
Różnica między wydarzeniami a delegatami jest o wiele mniejsza, niż sądziłem. Właśnie opublikowałem super krótki film na ten temat na YouTube: https://www.youtube.com/watch?v=el-kKK-7SBU
Mam nadzieję że to pomoże!
źródło
źródło