Czy nadawca zdarzenia powinien być zawsze obiektem ogólnym?

10

Podczas programowania zdarzeń w języku C # zaleca się utworzenie delegata w postaci:

delegate XEventHandler(object sender, XEventArgs e);

Moje pytanie jest na pierwszym argumencie delegata object sender. Czy zawsze musi być ogólny object? Posiadanie nadawcy typu objectzawsze skutkuje kodem podobnym do tego.

val = ((ConcreteType)sender).Property;

lub jeszcze bardziej gadatliwy

ConcreteType obj = sender as ConcreteType
if (obj != null) { ... }

Jednym argumentem przeciwko nadawcom o silnym typie jest to, że inne obiekty mogą przekazywać zdarzenie bez obawy o typ. Chociaż może to mieć sens w środowiskach GUI, nie jestem pewien, czy mogłoby to przynieść korzyści poza GUI.

Co się stanie, jeśli klasa nadawcy jest zawsze znana (przynajmniej jako klasa abstrakcyjna)? Na przykład, jeśli mam wdrożenia ListChangedzdarzenie w abstrakcyjnej Listklasy, a jeśli inne klasy będą dziedziczyć go (np LinkedList, ArrayList), to wszystko jest w porządku, aby określić mój delegata z nadajnikiem typu List?

delegate ListChangedEventHander(List sender, ListChangedEventArgs e);

Czy może miałoby to negatywne skutki zmiany modelu konwencjonalnego object senderna bardziej konkretny?

sampathsris
źródło

Odpowiedzi:

10

W tym momencie jest to głównie (dość silna) konwencja. To będzie dziwne, jeśli napiszesz bibliotekę, która nie przestrzega tej konwencji.

W wytycznych projektowych imprez powiedzieć:

DO wykorzystania objectjako typ pierwszego parametru obsługi zdarzeń, i nazwać sender.

Jednak możesz zauważyć, że obecne wytyczne mówią, że nie powinieneś definiować własnego niestandardowego delegata dla zdarzeń, ale EventHandler<T>zamiast tego użyj , jeśli możesz.

Jeśli chodzi o projekt, zgaduję, że promuje on także ponowne użycie procedur obsługi zdarzeń, nawet w kontekstach nieprzewidzianych pierwotnie przez projektanta zdarzenia.

jhominal
źródło
2
Ughhh ... tylko dlatego, że Microsoft postanowił uczynić swoje wytyczne wystarczająco ogólnymi, aby mogły być stosowane dla wszystkich, nie oznacza to, że dobrym pomysłem jest, aby wszyscy inni przestrzegali tych wytycznych. Szanse są bardzo prawdopodobne, że „wszyscy inni” nie piszą kodu do wykorzystania przez miliony innych programistów. Skuliłem się na około 2/3 rekomendacji z linku, który podałeś.
Dunk
Mówiąc prawdę, ta „wytyczna” przypomina mniej więcej węgierską notację Windows API. Ktoś genialny zaczął go z naprawdę dobrego powodu, a potem wszyscy inni zaczęli go nadużywać. Gdy istnieje wytyczna, lepiej być uzasadnionym powodem. I co ja myślę powodem tej wytycznej jest to, że System.Windows.Formsprzestrzeń nazw jest miejsce, gdzie są najbardziej intensywnie używane imprezy, i uczynił to sens, aby zapisać się na Clickwypadek Buttonlub CheckBox. Dlatego nadawca musi być ogólny. ...
sampathsris,
... Ale jeśli chodzi o inne, bardziej szczegółowe, zawarte obszary funkcjonalności, nadawca może nie być klasą ogólną. Zobacz jeszcze raz mój przykład hierarchii klas Lists.
sampathsris
11
@Dunk: I o to chodzi. Wytyczne te pochodzą z Wytycznych dotyczących projektowania ramowego, które dotyczą przede wszystkim kodu używanego przez innych . Nie dlatego, że jest to najlepsze rozwiązanie, ale dlatego, że jest najmniej zaskakujące. To najlepsza opcja dla frameworka . W przypadku mniejszych bibliotek, jeśli przypadek użycia jest dobrze określony, zastosowanie ma mniej wskazówek. Microsoft wyraźnie to mówi na początku książki.
Mag
1
Nie spieram się z odpowiedzią, nawet ją głosowałem, ponieważ pochodzi ona z renomowanego źródła. Mówię tylko, że nie skorzystałbym z wytycznych. Jeśli zdarzenie ma wysłać określone dane, wyślę tylko określone dane. Ponadto funkcja zdarzenia działa dobrze, jeśli używasz ich w sposób, w jaki były przeznaczone do użycia.
Dunk
0

Powodem tego zalecenia jest to, że umożliwia przyszłe zmiany, które niekoniecznie wymagają zmian w istniejącym kodzie, a zwłaszcza w interfejsie publicznym.

Sam mechanizm zdarzenia może być nadal używany w przypadku zdarzeń w stylu „VB6”, ale będziesz musiał zmienić wszystkich istniejących klientów, jeśli kiedykolwiek będziesz musiał zmienić podpis (lub gorzej: utwórz nowe wersje tych samych zdarzeń). Przy zalecanym podejściu, o ile nowsze elementy dziedziczą po istniejących, możesz zaktualizować podpis bez poprawiania istniejącego kodu.

Mark Hurd
źródło