Предпочтительный способ объявить события


14

Я довольно доволен своим пониманием модели событий .NET. Я думаю, что я мог неправильно понять небольшой нюанс системы.

Когда я начинал помещать события в свои классы, я использовал стандартный способ:

public event EventHandler<MyEventArgs> MyEvent;

Это означало, что для подписки на событие потребуется такой метод:

void HandleThatEvent(object sender, MyEventArgs args){...}

Это хорошо, но я обнаружил, что меня не очень заботит отправитель, поэтому многие подписи метода раздуты.

Поэтому я перешел к объявлению своих собственных типов делегатов

public delegate void MyEventHandler(SomeClass argument);

Который уменьшил беспорядок, но оставил мне небольшую проблему, когда дело дошло до написания обработчиков:

eventImplmentor.MyEvent += HandleThatEvent;
.
.
.
void HandleThatEvent(/*oh, um, what arguments does it take? Intellisense isn't telling me*/)

Поэтому мне придется вернуться к заявлению делегата и посмотреть, а затем вернуться и записать их или скомпилировать и дождаться, когда об этом скажут.

Так что теперь вместо этого я просто использую Action, Action<T>или любой другой шаблон подходит.

public event Action<SomeClass> MyEvent;

Так что я могу навести курсор на событие и узнать, какие параметры оно ожидает.

Мой вопрос, после всего этого: есть ли лучшая практика для объявления событий в C #? Должен ли я вернуться на EventHandler<T>путь, или это Action<T>приемлемо?


Не забудьте убедиться, что обработчик локально скопирован в то место, где вы запускаете событие, всегда делайте это для безопасности потоков.
Снуп

В инкапсулированном коде вы можете написать свои собственные разумные, безопасные и безопасные для типов события, но все, что вы публикуете, должно следовать стандартному шаблону, иначе это просто запутает пользователей вашего класса (и, очевидно, некоторых инструментов).
Мартин Маат

Ответы:


8

Для простой внутренней обработки событий есть такие, которые просто используют Actionили Action<T>, как вы предлагаете. Я склонен использовать стандартный шаблон, в том числе Sender, даже для внутренних событий, потому что вы никогда не знаете, когда позже вы захотите выставить класс или событие, и я бы не хотел наказания за необходимость рефакторинга метода события просто для того, чтобы сделать это публично.

Я согласен с вами, что сигнатура обработки событий немного тяжелее, чем должна быть для простых сценариев, но она хорошо спроектирована для обработки постепенной миграции, поскольку со временем могут потребоваться дополнительные аргументы события. В целом, я бы придерживался стандартного шаблона, тем более что, как вы заметили, вы получите надлежащую поддержку IntelliSense, только если вы это сделаете.

Для чего бы это ни стоило, я потратил некоторое время на это и придумал другой шаблон обработки событий : Подпись события в .NET - Использование строго отправленного типа «Отправитель»? , Цель здесь состояла не в том, чтобы удалить Отправителя, а в том, чтобы сделать его строго типизированным TSenderвместо «слабо типизированным» System.Object. Это работает очень хорошо; однако при этом вы теряете поддержку IntelliSense, поэтому возможен неудачный компромисс.

В целом, я бы придерживался стандартного шаблона, но интересно подумать о потенциально лучших способах сделать это.


Спасибо, что указали мне на ваш ТАК вопрос. Это очень интересно. Я до сих пор не понимаю, почему так важно, чтобы отправитель был обязательным. Большую часть времени меня не волнует отправитель. Это просто какое-то произвольное правило РС?
Мэтт Эллен

Нет, конечно, вы можете объявить своих делегатов так, как вам нравится. Это политика .NET всегда включать отправителя, и в этом нет ничего плохого.
Нил

@Neil: Я понимаю, что иногда это полезно, но я не всегда придерживаюсь политики, особенно потому, что MS рекомендует делать события по-своему. Одна из вещей, которые мне действительно нравятся в событиях, - это возможность разъединять классы. Если я включаю объект, то он снова подключается. Если это просто соответствие требованиям CLS, я могу с этим смириться.
Мэтт Эллен

Он снова подключается, только если вы используете объект отправителя, в противном случае не имеет значения, что указывается в качестве значения отправителя, поскольку вы его не используете. Зависимость существует только в том случае, если вам нужна зависимость. Я вижу, откуда вы, и если бы отправитель объекта исчез из всего кода с любого сервера на планете, я бы не спал по ночам.
Нил

Да, вы можете отправить 'null' в качестве отправителя, если вы действительно хотите ... Но, включив отправителя, сам обработчик события может отписаться, если он этого захочет. В целом, я бы сказал, что знание источника события, как правило, очень важно.
Майк Розенблюм
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.