C # простой Event Raising - использование «отправителя» против пользовательских EventArgs - PullRequest
17 голосов
/ 01 мая 2009

Рассмотрим этот сценарий. У меня есть объект, давайте назовем его .... Фу. 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 ]

9 голосов
/ 01 мая 2009

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

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

3 голосов
/ 01 мая 2009

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

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

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

Control.Invoke()

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

int i;
3 голосов
/ 01 мая 2009

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

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

public delegate void LoadedHandler(FooEventArgs args);

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

3 голосов
/ 01 мая 2009

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

2 голосов
/ 01 мая 2009

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

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

2 голосов
/ 01 мая 2009

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...