2008-09-24 3 views
19

Каждый раз, когда я начинаю в проекте C#, я получаю множество событий, которые просто нужно передать одному элементу. Я придерживаюсь с практикой EventHandler/EventArgs, но то, что я хочу сделать, это что-то вроде:.NET EventHandlers - общий или нет?

public delegate void EventHandler<T>(object src, EventArgs<T> args); 

public class EventArgs<T>: EventArgs { 

    private T item; 

    public EventArgs(T item) { 
    this.item = item; 
    } 

    public T Item { 
    get { return item; } 
    } 
} 

Позже, я могу иметь мой

public event EventHandler<Foo> FooChanged; 

public event EventHandler<Bar> BarChanged; 

Тем не менее, кажется, что стандарт для .NET заключается в создании нового делегата и подкласса EventArgs для каждого типа событий. Что-то не так с моим общим подходом?


EDIT: Причина этого сообщения в том, что я только что заново создал это в новом проекте и хотел убедиться, что все в порядке. На самом деле, я воссоздал его, когда я разместил его. Я обнаружил, что существует общий EventHandler<TEventArgs>, поэтому вам не нужно создавать общий делегат, но вам все равно нужен общий класс EventArgs<T>, потому что TEventArgs: EventArgs.
Другой EDIT: Один недостаток (для меня) встроенного в растворе является дополнительным подробность:

public event EventHandler<EventArgs<Foo>> FooChanged; 

против

public event EventHandler<Foo> FooChanged; 

Это может быть боль для клиентов, чтобы зарегистрироваться для вашего события, потому что пространство имен System импортировано по умолчанию, поэтому им приходится вручную искать свое пространство имен даже при помощи привлекательного инструмента, такого как Resharper ... У кого-нибудь есть идеи, связанные с этим?

+1

Для стиля CRUD, о котором вы упоминали в другом комментарии, у меня был бы EntityEventHandler , который был бы самоописательным. – 2008-09-24 20:39:36

+1

вы можете добавить: с помощью FooArgs = Namespace.EventArgs ; который очистит событие до - public event EventHandler FooChanged; – Fraser 2012-04-25 13:38:18

ответ

26

Делегат из следующих форма была добавлена, так как .NET Framework 2,0

public delegate void EventHandler<TArgs>(object sender, TArgs args) where TArgs : EventArgs 

вы подход идет немного дальше, так как вы предоставляете вне коробки для осуществления EventArgs с одного элемента данных, но ему не хватает нескольких свойств оригинальной идеи :

  1. Вы не можете добавить дополнительные данные к данным события без изменения зависимого кода. Вам нужно будет изменить подпись делегата, чтобы предоставить больше данных подписчику события.
  2. Ваш объект данных является общим, но он также «анонимный», и при чтении кода вам придется расшифровать свойство «Item» из обычаев. Он должен быть назван в соответствии с данными, которые он предоставляет.
  3. Использование дженериков таким образом, вы не можете выполнить параллельную иерархию EventArgs, если у вас есть иерархия базовых типов (элементов). Например. EventArgs <BaseType> не является базовым типом для EventArgs <DerivedType>, даже если BaseType является базой для DerivedType.

Так что, я думаю, что лучше использовать общие EventHandler <T>, но до сих пор пользовательские EventArgs классы, организованные в соответствии с требованиями модели данных. С Visual Studio и расширениями, такими как ReSharper, для создания нового класса требуется всего несколько команд.

7

Нет, я не думаю, что это неправильный подход. Я думаю, что это даже рекомендуется в [фантастической] книге Framework Design Guidelines. Я делаю то же самое.

1

Я действительно верю, что в последних версиях .NET есть только такой обработчик событий, определенный в них. Насколько мне известно, это большие пальцы.

/EDIT

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

+0

В последних версиях есть общий делегат, но у них нет однофакторных EventArgs – 2008-09-24 20:00:36

3

Это правильная реализация. Он был добавлен в .NET Framework (mscorlib), так как вначале появились generics (2.0).

Более подробную информацию о его использовании и реализации см MSDN: http://msdn.microsoft.com/en-us/library/db0etb8x.aspx

3

В первый раз, когда я увидел этот маленький узор, я использовал Composite UI Application block, от MS Patterns & Практики группы.

Он не бросает мне никакого красного флага; на самом деле это даже разумный способ использования дженериков для соблюдения правила DRY.

2

Вы можете найти Generic EventHandler на MSDN http://msdn.microsoft.com/en-us/library/db0etb8x.aspx

Я использую общий EventHandler широко и был в состоянии предотвратить так называемые «Взрыв типов (классов)» Project хранился меньше и легче перемещаться.

Далее с новым интуитивным делегата для необщего EventHandler делегат является болезненным и пересекаться с существующими типами Добавление данных «* EventHandler» на новое имя делегата не очень помогает, на мой взгляд

9

Чтобы упростить создание описания событий, я создал для него несколько фрагментов кода. Для их использования:

  • Скопируйте весь фрагмент.
  • Вставьте его в текстовый файл (например, в блокнот).
  • Сохраните файл с расширением .snippet.
  • Поместите .snippet файл в соответствующем каталоге сниппеты, например:

Visual Studio 2008 \ фрагментов коды \ Visual C# \ Моих фрагментов кода

Вот один, который использует пользовательский класс EventArgs с одно свойство:

<?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 one type/argument.</Title> 
      <Shortcut>ev1Generic</Shortcut> 
      <Description>Code snippet for event handler and On method</Description> 
      <Author>Kyralessa</Author> 
      <SnippetTypes> 
       <SnippetType>Expansion</SnippetType> 
      </SnippetTypes> 
     </Header> 
     <Snippet> 
      <Declarations> 
     <Literal> 
      <ID>type</ID> 
      <ToolTip>Type of the property in the EventArgs subclass.</ToolTip> 
      <Default>propertyType</Default> 
     </Literal> 
     <Literal> 
      <ID>argName</ID> 
      <ToolTip>Name of the argument in the EventArgs subclass constructor.</ToolTip> 
      <Default>propertyName</Default> 
     </Literal> 
     <Literal> 
      <ID>propertyName</ID> 
      <ToolTip>Name of the property in the EventArgs subclass.</ToolTip> 
      <Default>PropertyName</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($type$ $argName$) 
     { 
      this.$propertyName$ = $argName$; 
     } 

     public $type$ $propertyName$ { 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> 

И вот один, который имеет два свойства:

<?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>propertyType1</Default> 
     </Literal> 
     <Literal> 
      <ID>arg2Name</ID> 
      <ToolTip>Name of the second argument in the EventArgs subclass constructor.</ToolTip> 
      <Default>property1Name</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> 

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

1

Использовать общие события экземпляры обработчика

Перед .NET Framework 2.0, для того, чтобы передать информацию о пользовательских обработчик событий, новый делегат должен был быть объявлен, что указанный класс, производный от класса System.EventArgs. Это больше не относится к .NET.

Framework 2.0, в котором представлен делегат System.EventHandler < T>). Этот общий делегат позволяет использовать любой класс, полученный из EventArgs, с обработчиком событий.

Смежные вопросы