Как неправильно создавать делегат обработчика событий без стандартного (Obj sender, EventArgs args) подписи?

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

Что мне интересно на практике, как часто люди следуют этому правилу? Скажем, у меня такое простое событие

public event NameChangedHandler NameChanged;
public delegate void NameChangedHandler(Object sender, string oldName, string newName);

Это простое событие, и я почти уверен, что единственным аргументом, который мне когда-либо понадобится знать из события NameChanged, является объект, имя которого изменено, старое имя и новое имя. Так стоит ли создавать отдельный класс NameChangedEventArgs, или для простых событий, подобных этому, приемлемо ли просто возвращать аргументы напрямую через аргументы делегата?

Ответ 1

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

Итак, я сделаю вам сделку. Если вы обещаете сделать это правильно, я дам вам фрагмент кода, который сделает его гораздо менее болезненным. Просто поместите это в файл .snippet и поместите этот файл в:

Мои документы \Visual Studio 2008\Фрагменты кода \Visual С#\Мои фрагменты кода \
(или Visual Studio 2005, если применимо)

И вот фрагмент; используйте его в VS, набрав ev2Generic и нажав Tab:

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>Generic event with two types/arguments.</Title>
      <Shortcut>ev2Generic</Shortcut>
      <Description>Code snippet for event handler and On method</Description>
      <Author>Kyralessa</Author>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>type1</ID>
          <ToolTip>Type of the first property in the EventArgs subclass.</ToolTip>
          <Default>propertyType1</Default>
        </Literal>
        <Literal>
          <ID>arg1Name</ID>
          <ToolTip>Name of the first argument in the EventArgs subclass constructor.</ToolTip>
          <Default>property1Name</Default>
        </Literal>
        <Literal>
          <ID>property1Name</ID>
          <ToolTip>Name of the first property in the EventArgs subclass.</ToolTip>
          <Default>Property1Name</Default>
        </Literal>
        <Literal>
          <ID>type2</ID>
          <ToolTip>Type of the second property in the EventArgs subclass.</ToolTip>
          <Default>propertyType2</Default>
        </Literal>
        <Literal>
          <ID>arg2Name</ID>
          <ToolTip>Name of the second argument in the EventArgs subclass constructor.</ToolTip>
          <Default>property2Name</Default>
        </Literal>
        <Literal>
          <ID>property2Name</ID>
          <ToolTip>Name of the second property in the EventArgs subclass.</ToolTip>
          <Default>Property2Name</Default>
        </Literal>
        <Literal>
          <ID>eventName</ID>
          <ToolTip>Name of the event</ToolTip>
          <Default>NameOfEvent</Default>
        </Literal>
      </Declarations>
      <Code Language="CSharp">
        <![CDATA[public class $eventName$EventArgs : System.EventArgs
      {
        public $eventName$EventArgs($type1$ $arg1Name$, $type2$ $arg2Name$)
        {
          this.$property1Name$ = $arg1Name$;
          this.$property2Name$ = $arg2Name$;
        }

        public $type1$ $property1Name$ { get; private set; }
        public $type2$ $property2Name$ { get; private set; }
      }

      public event EventHandler<$eventName$EventArgs> $eventName$;
            protected virtual void On$eventName$($eventName$EventArgs e)
            {
                var handler = $eventName$;
                if (handler != null)
                    handler(this, e);
            }]]>
      </Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

Ответ 2

Используйте EventHandler<T> общие делегаты для ваших событий и создайте тип, полученный из EventArgs, для хранения данных о событиях. То есть, другими словами, всегда. Это то, что вы всегда точно знаете, как это работает, когда вы сталкиваетесь с ним, потому что он никогда не делал иначе.

Edit:

Анализ кода CA1003: используйте общие экземпляры обработчика событий
Анализ кода CA1009: правильно объявить обработчики событий

Ответ 3

На практике, как часто люди [не используйте производные классы EventArgs].

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

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

Вы, кажется, говорите, что будете использовать EventArgs для обработчиков событий с большим количеством параметров и не использовать его для таких случаев. Честно говоря, это просто не вариант при программировании на С#. Согласованность - это необходимость, особенно в сегодняшнем мире таких форумов, проектах с открытым исходным кодом и т.д., Где легко его потерять. Конечно, если вы программируете это под скалой, вы можете делать все, что захотите, но большее сообщество С# благодарит вас за следующие стандарты и особенно за использование последовательности в вашем коде.