С# simple Event Raising - использование "отправителя" и пользовательских EventArgs
Рассмотрим этот сценарий. У меня есть объект, позвольте назвать его.... Foo. 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 действительно ломается, поэтому его можно зафиксировать во время компиляции.
Мне кажется, что этот шаблон кажется излишним. Должны ли они больше доверять параметру "отправитель" и отбрасывать аргументы настраиваемого события? Моя команда утверждает, что никто не использует параметр отправителя. Какая наилучшая практика для передачи ссылки на объект, создающий событие?
EDIT: Отличная обратная связь до сих пор, я оставлю это открытым еще на один день или около того, прежде чем принять его.
Ответы
Ответ 1
Общий шаблон - использовать отправителя и не добавлять отправителя отдельно к EventArgs. Пользовательские EventArgs используются для другого состояния, такого как дерево node для события дерева, (устанавливаемого) логического для события отмены и т.д.
Мы используем общий шаблон, так как он также используется классами BCL, а внесение изменений в "самодельные события" потенциально запутывает. Кроме того, у нас есть глобальный шаблон подписчика издателя IoC, но этот работает только с обычной подписью делегата EventHandler, так как типы не известны заранее. В этом случае приведение в действие (например, к пользовательскому EventArgs) необходимо в любом случае, поэтому мы можем просто отбросить отправителя.
Ответ 2
Я не думаю, что это слишком много. Я согласен с преимуществами, которые вы заявляете в отношении наличия отдельного класса FooEventArgs. Другим преимуществом для этого является то, что если вам нужно добавить дополнительную информацию к событию в будущем, вы можете просто добавить дополнительные свойства в FooEventArgs, и вам не нужно будет менять делегат.
Ответ 3
Я бы сказал, что вы отбрасываете подкласс EventArgs и используете свойство отправителя для идентификации отправителя события. Я считаю, что аргумент для следующего соглашения имеет смысл, но параметр в EventArg не нужен. Я лично брошу его и просто использую свойство отправителя.
Если вы хотите передать его как сильный тип, вы также можете просто создать пользовательский делегат, который будет использоваться для вашего события...
public delegate void LoadedHandler(FooEventArgs args);
таким образом вы могли бы использовать его как сильный тип... повторное использование делегатов велико, но если они не подходят к тому, что вы пытаетесь сделать, вам не следует ограничивать использование только встроенных.
Ответ 4
Я бы сказал, что у конвенции есть много всего для этого. Меньше поддерживать в долгосрочной перспективе - особенно. если вы получаете новых людей.
Ответ 5
Я думаю, это вопрос предпочтения в какой-то степени, но в моем случае, когда я читал consumers will need to know which foo object raised the event.
, я сразу подумал, что вы можете получить объект, который поднял событие из аргумента отправителя, и что проблема?
У вашей команды есть некоторые действительные баллы (при наличии строго типизированного свойства), но я бы сказал, что работа с руководящими принципами в области разработки, а не придумывание собственных, будет лучшим решением в долгосрочной перспективе.
Ответ 6
Что касается рекомендуемых практик, я видел, что null в качестве отправителя в Windows Workflow Foundation довольно много. В идеале, ваши подписчики должны не обращать внимания на объект, который вызывает события.
Итак, если вам нужно передать объект-вызывающий объект в целом обработчикам, вы должны поместить его в объект, созданный EventArgs. В качестве альтернативы, я предпочитаю явно передавать бит и куски состояния рейзера/вызывающего события, а не всего.
Ну, иногда проще думать dotNET 1.1, где
Control.Invoke()
используется так часто, как
int i;