Кодовая версия подписи события в .NET - PullRequest
4 голосов
/ 11 ноября 2010

Предыдущие записи:

Подпись события в .NET - Использование строго отправленного типа «Отправитель»?

Почему в обработчике событий C # параметр «отправитель» должен быть объектом?


Соглашения и руководства Microsoft заставляют пользователей .NET использовать специальные шаблоны для создания, создания и обработки событий в .NET.

Руководство по разработке событий http://msdn.microsoft.com/en-us/library/ms229011.aspx утверждает, что


Образец цитирования:

Подпись обработчика событий соблюдает следующие соглашения:

  • Тип возврата Void.

  • Первый параметр называется отправителем и имеет тип Object. Это объект, вызвавший событие.

  • Второй параметр называется e и имеет тип EventArgs или производный класс EventArgs. Это специфичные для события данные.

  • Метод занимает ровно два параметры.


Эти соглашения говорят разработчикам, что (следующий) более короткий и очевидный код является злом:

public delegate void ConnectionEventHandler(Server sender, Connection connection);

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, connection);
    }

    public event ConnectionEventHandler ClientConnected;
}

и (следующий) более длинный и менее очевидный код - это хорошо:

public delegate void ConnectionEventHandler(object sender, ConnectionEventArgs e);

public class ConnectionEventArgs : EventArgs
{
    public Connection Connection { get; private set; }

    public ConnectionEventArgs(Connection connection)
    {
        this.Connection = connection;
    }
}

public partial class Server
{
    protected virtual void OnClientConnected(Connection connection)
    {
        if (ClientConnected != null) ClientConnected(this, new ConnectionEventArgs(connection));
    }

    public event ConnectionEventHandler ClientConnected;
}

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

ИМХО, соглашения Microsoft о подписи событий для .NET вредны для вашего кода, потому что они требуют дополнительных усилий с нулевой эффективностью для кодирования, кодирования, кодирования:

  1. Кодирование «(MyObject) sender» приводит (не говоря уже о 99% ситуаций, которые вообще не требуют отправителя)
  2. Кодирование производного «MyEventArgs» для данных, передаваемых в обработчик событий.
  3. Кодирование разыменования (вызов «e.MyData», когда требуются данные, а не просто «данные»)

Это не так сложно сделать, но практически говорить о том, что мы теряем, когда не соблюдаем соглашения Microsoft, за исключением того, что люди воспринимают вас как еретика, потому что ваш акт противостояния соглашениям Microsoft граничит с богохульством :)

Согласны ли вы?

Ответы [ 4 ]

3 голосов
/ 11 ноября 2010

Проблемы, с которыми вы столкнетесь:

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

  2. Когда программист впервые просматривает ваш код, ваши обработчики событий не будут похожи на обработчики событий.

Тем более, что последний может тратить вас впустуюбольше времени, чем на написание класса из 5 строк.

3 голосов
/ 11 ноября 2010

Относительно наличия строго типизированного отправителя, я часто задавался вопросом, что сам.

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

Редактировать

Джим Мишел хорошо высказался в своих комментариях.Делая отправителя object, мы позволяем одному и тому же методу события потенциально использоваться повторно для обработки различных событий.Например, скажем, что сетка должна обновляться сама, если:

  • пользователь нажимает кнопку «обновить», или
  • система обнаруживает, что новая запись была загружена изсервер.

Затем вы могли бы сказать что-то вроде этого:

serverBus.EntryReceived += RefreshNeededHandler;
refreshButton.Click += RefreshNeededHandler;

...
public void RefreshNeededHandler(object sender, EventArgs args) 
{
    ...
}

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

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

2 голосов
/ 11 ноября 2010

Самая большая проблема, которую я вижу в несоблюдении соглашения, состоит в том, что вы будете путать разработчиков, которые привыкли обрабатывать события так, как это делает библиотека времени выполнения. Я не скажу, что соглашение хорошее или плохое, но оно определенно не зло . Разработчики .NET знают и понимают, как работать с событиями, написанными в соответствии с рекомендациями Microsoft. Создание собственного механизма обработки событий может быть более эффективным во время выполнения и даже может привести к созданию кода, который вы считаете более чистым. Но все будет иначе, и в вашей программе появятся два «стандарта» обработки событий.

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

1 голос
/ 12 ноября 2010

Я использовал строго типизированные события (вместо объекта, поскольку это спасает меня от приведения), это действительно не так сложно понять, «о, смотрите, они использовали тип, который не является объектом»

Что касается eventArgs, вы должны использовать это в случае, если объект изменяется согласно ответу @StriplingWarrior.

Я не понимаю, почему разработчики могут запутаться из-за этого?

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