C# простой Event Raising - использование "отправителя" против пользовательских EventArgs

Рассмотрим этот сценарий. У меня есть объект, давайте его назовем.... Фу. Foo вызывает простое событие под названием "Loaded". Как часть информации для события, потребители должны будут знать, какой объект foo вызвал событие. Наша команда приняла следующую схему.

1) Создайте новый класс, который наследуется от EventArgs - например, FooEventArgs: System.EventArgs.

2) Добавьте свойство типа Foo в FooEventArgs, которое устанавливается путем передачи через конструктор.

3) Объявите событие, используя общую версию EventHandler, так

public event EventHandler<FooEventArgs> Loaded;

4) Создайте событие из класса Foo со следующей подписью:

Loaded(this, new FooEventArgs(this));

По сути, это делает "отправителя" объектом foo, но он также помещает ссылку на объект foo в аргумент события как строго типизированное свойство.

Одним из преимуществ этого является то, что никто не должен беспокоиться о приведении "отправителя", когда они обрабатывают событие, что снижает связь между потребителем события и источником события. Другое "преимущество" заключается в том, что если когда-либо должен измениться тип сборщика событий и, следовательно, строго типизированное свойство (что, мы надеемся, никогда не произойдет), то вместо простого запуска кода происходит сбой при приведении, когда он выходит как ноль, API фактически ломается, поэтому его можно исправить во время компиляции.

Мне кажется, что эта модель может быть излишней. Должны ли они больше доверять параметру "отправитель" и игнорировать аргументы пользовательских событий? Моя команда утверждает, что на самом деле никто не использует параметр отправителя. Как лучше всего передавать ссылку на объект, вызывающий события?

РЕДАКТИРОВАТЬ: Отличная обратная связь до сих пор, я оставлю это открытым на другой день или около того, прежде чем я приму один.

6 ответов

Решение

Обычный шаблон - использовать отправителя, а не добавлять отправителя отдельно в EventArgs. Пользовательские EventArgs используются для другого состояния, например, узла дерева для события дерева, (устанавливаемого) логического значения для отменяемого события и т. Д.

Мы используем общий шаблон, так как он также используется классами BCL, и создание различий для "самодельных событий" может привести к путанице. Кроме того, у нас есть глобальный шаблон издателя-подписчика IoC, но этот работает только с обычной подписью делегата EventHandler, так как типы заранее не известны. В этом случае в любом случае необходимо приведение (например, к пользовательскому EventArgs), поэтому мы могли бы с тем же успехом привести и отправителя.

Что касается рекомендуемых практик, я видел, что null поставлялся как отправитель в Windows Workflow Foundation. В идеале, ваши подписчики должны не обращать внимания на объект, который вызывает события.

Поэтому, если вам нужно передать объект вызывающего объекта целиком обработчикам, вам нужно будет поместить его в объект, полученный из EventArgs. С другой стороны, я предпочитаю явно передавать биты и кусочки состояния сборщика / вызывающего события вместо всего этого.

Ну, иногда проще думать о dotNET 1.1, где

Control.Invoke()

используется так часто, как

int i;

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

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

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

public delegate void LoadedHandler(FooEventArgs args);

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

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

Я предполагаю, что это в какой-то степени предпочтение, но в моем случае, когда я читаю consumers will need to know which foo object raised the event. Я сразу подумал, что вы можете получить объект, вызвавший событие, из аргумента отправителя, так в чем же проблема?

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

Другие вопросы по тегам