Jestem całkiem zadowolony ze zrozumienia modelu zdarzeń .NET. Myślę, że nie rozumiem małego niuansu systemu.
Kiedy zacząłem umieszczać wydarzenia na moich zajęciach, używałbym standardowego sposobu:
public event EventHandler<MyEventArgs> MyEvent;
Oznaczało to, że do subskrybowania tego wydarzenia potrzebna byłaby metoda taka jak:
void HandleThatEvent(object sender, MyEventArgs args){...}
Co jest miłe, ale okazało się, że rzadko dbam o nadawcę, więc spowodowało to rozdęcie wielu podpisów metod.
Więc przeszedłem do deklarowania własnych typów delegatów
public delegate void MyEventHandler(SomeClass argument);
Co zmniejszyło bałagan, ale pozostawiło mi mały problem, jeśli chodzi o pisanie programów obsługi:
eventImplmentor.MyEvent += HandleThatEvent;
.
.
.
void HandleThatEvent(/*oh, um, what arguments does it take? Intellisense isn't telling me*/)
Musiałbym więc wrócić do deklaracji delegata i poszukać, a następnie wrócić i napisać je lub skompilować i poczekać, aż usłyszę wiadomość.
Więc teraz zamiast, po prostu przy użyciu Action
, Action<T>
lub cokolwiek szablon pasuje.
public event Action<SomeClass> MyEvent;
Abym mógł najechać kursorem na zdarzenie i dowiedzieć się, jakich parametrów oczekuje.
Moje pytanie po tym wszystkim: czy istnieje najlepsza praktyka do deklarowania wydarzeń w C #? Czy powinienem wrócić do EventHandler<T>
drogi, czy jest to do Action<T>
przyjęcia?
Odpowiedzi:
Dla prostej, wewnętrznej obsługi zdarzeń, są takie, które po prostu wykorzystują
Action
lubAction<T>
, jak proponujesz. Zwykle używam standardowego wzorca, w tym Nadawcy, nawet do zdarzeń wewnętrznych, ponieważ nigdy nie wiadomo, kiedy możesz chcieć później ujawnić klasę lub zdarzenie, i nie chciałbym kary za konieczność zmiany metody zdarzenia tylko po to, aby zrobić to publiczne.Zgadzam się z tobą, że podpis obsługi zdarzenia jest nieco cięższy niż powinien być w przypadku prostych scenariuszy, ale jest dobrze zaprojektowany do obsługi przyrostowej migracji, ponieważ z czasem mogą być potrzebne dodatkowe argumenty zdarzeń. Ogólnie rzecz biorąc, trzymałbym się standardowego wzorca, zwłaszcza, że, jak zauważyłeś, dostaniesz odpowiednią obsługę IntelliSense tylko wtedy, gdy to zrobisz.
Za ile warto, poświęciłem temu trochę czasu i wymyśliłem inny wzorzec obsługi zdarzeń : Podpis zdarzenia w .NET - Używanie silnego „nadawcy”? . Celem tutaj nie było usunięcie nadawcy, ale sprawienie, aby generalnie był on silnie wpisany jako
TSender
zamiast słabo wpisany jakoSystem.Object
. Pracuje bardzo dobrze; jednak traci się wtedy obsługę IntelliSense, więc następuje niefortunny kompromis.Ogólnie rzecz biorąc, trzymałbym się standardowego wzorca, ale interesujące jest zastanowienie się nad potencjalnie lepszymi sposobami na zrobienie tego.
źródło