23

C# プロジェクトを深く掘り下げるたびに、本当に 1 つの項目を渡す必要があるだけのイベントが大量に発生します。EventHandler私は/の練習に固執しEventArgsますが、私がやりたいのは次のようなものです:

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;

EventArgsただし、.NET の標準では、イベントの種類ごとに新しいデリゲートとサブクラスを作成するようです。私の一般的なアプローチに何か問題がありますか?


編集: この投稿の理由は、これを新しいプロジェクトで再作成したばかりで、問題がないことを確認したかったからです。実は、投稿したとおりに作り直していました。ジェネリックがあることがわかったEventHandler<TEventArgs>ので、ジェネリックデリゲートを作成する必要はありませんが、ジェネリックEventArgs<T>クラスはまだ必要TEventArgs: EventArgsです.
別の編集:組み込みソリューションの(私にとって)1つの欠点は、余分な冗長性です:

public event EventHandler<EventArgs<Foo>> FooChanged;

対。

public event EventHandler<Foo> FooChanged;

ただし、システム名前空間はデフォルトでインポートされるため、クライアントがイベントに登録するのは面倒な場合があります。そのため、Resharper のような派手なツールを使用しても、手動で名前空間を探す必要があります...誰にでもそれに関連するアイデアがあります?

4

9 に答える 9

28

.NET Framework 2.0 から次の形式のデリゲートが追加されました。

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

単一のデータ項目を使用して EventArgs のすぐに使用できる実装を提供するため、アプローチはもう少し進みますが、元のアイデアのいくつかのプロパティが欠けています。

  1. 依存するコードを変更しない限り、イベント データにプロパティを追加することはできません。イベント サブスクライバーにより多くのデータを提供するには、デリゲート シグネチャを変更する必要があります。
  2. データ オブジェクトは一般的ですが、「匿名」でもあります。コードを読みながら、用途から「Item」プロパティを解読する必要があります。提供するデータに従って名前を付ける必要があります。
  3. このようにジェネリックを使用すると、基になる (項目) 型の階層がある場合、EventArgs の並列階層を作成できません。たとえば、BaseType が DerivedType のベースであっても、EventArgs<BaseType> は EventArgs<DerivedType> のベース タイプではありません。

したがって、ジェネリック EventHandler<T> を使用する方が良いと思いますが、データ モデルの要件に従って編成されたカスタム EventArgs クラスを使用します。Visual Studio と ReSharper などの拡張機能を使用すると、コマンドを実行するだけでそのような新しいクラスを作成できます。

于 2008-09-24T20:13:36.127 に答える
9

一般的なイベントの宣言を簡単にするために、いくつかのコード スニペットを作成しました。それらを使用するには:

  • スニペット全体をコピーします。
  • テキスト ファイルに貼り付けます (メモ帳など)。
  • .snippet 拡張子を付けてファイルを保存します。
  • 次のような適切なスニペット ディレクトリに .snippet ファイルを配置します。

Visual Studio 2008\コード スニペット\Visual C#\マイ コード スニペット

以下は、1 つのプロパティを持つカスタム 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>Ryan Lundy</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>
      <Imports>
        <Import>
          <Namespace>System</Namespace>
        </Import>
      </Imports>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

そして、これは 2 つのプロパティを持つものです。

<?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>Ryan Lundy</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>
      <Imports>
        <Import>
          <Namespace>System</Namespace>
        </Import>
      </Imports>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

パターンに従って、好きなだけ多くのプロパティでそれらを作成できます。

于 2008-09-24T20:37:38.643 に答える
8

いいえ、これが間違ったアプローチだとは思いません。[素晴らしい] 本Framework Design Guidelinesでさえ推奨されていると思います。私も同じことをします。

于 2008-09-24T19:52:53.680 に答える
3

これは正しい実装です。ジェネリックが最初に利用可能になったとき (2.0) に、.NET Framework (mscorlib) に追加されました。

使用法と実装の詳細については、MSDN を参照してください: http://msdn.microsoft.com/en-us/library/db0etb8x.aspx

于 2008-09-24T20:00:23.583 に答える
3

この小さなパターンを初めて見たとき、MS Patterns & Practices グループのComposite UI Application ブロックを使用していました。

それは私に危険信号を投げません。実際、ジェネリックを活用してDRYルールに従うのは賢明な方法です。

于 2008-09-24T20:05:43.323 に答える
2

.NET 2.0 以降

EventHandler<T>

が実装されました。

于 2008-09-24T20:00:56.437 に答える
2

MSDN http://msdn.microsoft.com/en-us/library/db0etb8x.aspxで Generic EventHandler を見つけることができます。

私はジェネリック EventHandler を広範囲に使用しており、いわゆる「タイプ (クラス) の爆発」を防ぐことができました。プロジェクトは小さく保たれ、ナビゲートしやすくなりました。

非ジェネリックな EventHandler デリゲートの新しい直感的なデリゲートを考え出すのは苦痛であり、既存の型と重複する 新しいデリゲート名に "*EventHandler" を追加することは、私の意見ではあまり役に立ちません

于 2008-09-24T20:10:44.777 に答える
1

.NET の最近のバージョンには、そのようなイベント ハンドラーが定義されていると思います。私に関する限り、それは大きな親指です。

/編集

もともとそこに違いはありませんでした。EventArgs を継承するクラスを返す限り、問題はありません。保守性の理由から結果をラップしていない場合は心配です。今でも似合うと言っています。

于 2008-09-24T19:57:51.593 に答える
1

汎用イベント ハンドラー インスタンスを使用する

.NET Framework 2.0 より前は、カスタム情報をイベント ハンドラーに渡すために、System.EventArgs クラスから派生したクラスを指定する新しいデリゲートを宣言する必要がありました。これは、.NET では当てはまりません。

System.EventHandler<T>) デリゲートを導入した Framework 2.0。このジェネリック デリゲートにより、EventArgs から派生した任意のクラスをイベント ハンドラーで使用できます。

于 2010-04-12T08:39:53.517 に答える