Чи повинен відправник події завжди бути загальним Об’єктом?


10

При програмуванні подій на C # рекомендується створити делегата у вигляді:

delegate XEventHandler(object sender, XEventArgs e);

Моє питання на перший аргумент делегата object sender. Чи завжди це має бути родовим object? Наявність відправника типу objectзавжди призводить до коду, подібного до цього.

val = ((ConcreteType)sender).Property;

або, ще більш багатослівний,

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

Один з аргументів проти сильно набраних відправників - це те, що інші об'єкти можуть пересилати подію, не переживаючи про тип. Хоча це може мати сенс у середовищі графічного інтерфейсу, я не впевнений, чи може це отримати користь поза графічним інтерфейсом.

Що робити, якщо клас відправника завжди відомий (принаймні як абстрактний клас)? Наприклад, якщо я реалізую ListChangedподію в абстрактному Listкласі, і якщо інші класи збираються успадкувати його (наприклад LinkedList, ArrayList), чи все в порядку визначити мого делегата із типом відправника List?

delegate ListChangedEventHander(List sender, ListChangedEventArgs e);

Або, чи не буде змінити звичайний object senderна більш конкретний тип?

Відповіді:


10

На даний момент це здебільшого (досить сильна) конвенція. Тобто, це буде дивно, якщо ви напишете бібліотеку, яка не відповідає цій конвенції.

Правила дизайну подій кажуть:

DO використовувати objectяк тип першого параметра обробника подій, і викликати його sender.

Однак ви можете зауважити, що поточні вказівки говорять, що ви не повинні визначати власний спеціальний делегат для подій, а використовувати EventHandler<T>натомість, якщо можете.

Що стосується дизайну, я б здогадався, що він також сприяє повторному використанню обробників подій, навіть у контекстах, які спочатку не передбачалося оригінальним дизайнером події.


2
Так, адже те, що Microsoft вирішила зробити їхні керівні принципи достатньо загальними для того, щоб бути застосовними для всіх, не означає, що для всіх інших це гарна ідея виконувати їх вказівки. Швидше за все шанси, що "всі інші" не пишуть код, який використовуються мільйонами інших розробників. Я подав приблизно 2/3 рекомендацій із наданого вами посилання.
Данк

Якщо говорити правду, ця "настанова" більш-менш відчуває себе як угорська нотація API API. Хтось геніальний почав це з дійсно доброї причини, а потім усі інші почали зловживати цим. Коли є вказівки, то для цього краще бути вагомою причиною. І, на мою думку, причиною цього настанови є те, що System.Windows.Formsпростір імен - це місце, де події найбільш активно використовуються, і має сенс підписатися на Clickподію Buttonабо CheckBox. Таким чином, відправник повинен бути загальним. ...
sampathsris

... Але якщо мова йде про інші, більш конкретні, що містяться області функціональності, відправник, можливо, не повинен бути загальним класом. Дивіться ще раз мій приклад ієрархії класів Lists.
sampathsris

11
@Dunk: І в цьому справа. Це керівництво походить від Рамкових рекомендацій щодо дизайну, які стосуються насамперед коду, який споживають інші . Не тому, що це найкраще рішення, а тому, що це найменше дивно. Це найкращий варіант для рамки . Для менших бібліотек, якщо випадок використання чітко визначений, застосовується менше інструкцій. Microsoft прямо говорить на початку книги.
Магз

1
Я не сперечаюся з відповіддю, я навіть схвалив її, бо вона походить з авторитетного джерела. Я просто кажу, що не буду використовувати ці вказівки. Якщо подія повинна надіслати конкретні дані, я просто надішлю конкретні дані. Крім того, функція події працює чудово, якщо ви використовуєте їх як вони були призначені для використання.
Данк

0

Причина рекомендації полягає в тому, що вона дозволяє проводити майбутні зміни, які не обов'язково потребують змін до існуючого коду, і особливо публічного інтерфейсу.

Сам механізм подій все ще може використовуватися для подій у стилі "VB6", але вам доведеться змінити всіх існуючих споживачів, якщо вам коли-небудь потрібно змінити підпис (або ще гірше: створити нові версії тих же подій). За допомогою рекомендованого підходу, поки нові елементи успадковуються від існуючих, ви можете оновити підпис, не виправляючи існуючий код.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.