web-dev-qa-db-ja.com

C#のイベント(送信者、EventArgs)を取得する必要があるのはなぜですか?

パラメータとして取るイベントを宣言する必要があることが知られています(object sender, EventArgs args)。どうして?

37
ripper234

これにより、消費する開発者は、送信者やイベントに関係なく、複数のイベントに対して単一のイベントハンドラーを作成できます。

編集:なぜ別のパターンが必要なのですか? EventArgsを継承して任意の量のデータを提供できます。パターンを変更すると、この新しいパターンを消費せざるを得ない開発者を混乱させ、苛立たせるだけです。

22
Greg Hurlman

実際、これがイベントを行うためのベストプラクティスの方法であるかどうかについては議論の余地があります。イベントはコードの2つのセグメントを分離することを目的としているため、イベントハンドラーが送信者を取得し、それを使用して何かを行うために送信者をキャストするタイプを認識しなければならないという考え方があります。パターン。

11
user6288

言語に関係なく、あらゆるコールバックメカニズムに適したパターンだからです。誰がイベントを送信したか(送信者)、およびイベントに関連するデータ(EventArgs)を知りたいとします。

6
Eric Z Beard

イベントによって渡されるデータに単一のパラメーターEventArgsを使用すると、既存のコンシューマーを壊すことなく、ソフトウェアの将来のバージョンでイベントにデータを追加できます。既存のEventArgs派生クラスに新しいメンバーを追加するか、新しいメンバーを使用して派生クラスを作成するだけです。

それ以外の場合、一貫性と驚き最小の原則は、データを渡すためにEventArgsを使用することを正当化します。

送信者に関しては、すべてではありませんが、一部のケースでは、どのタイプがイベントを送信したかを知っておくと便利です。送信者引数にオブジェクト以外のタイプを使用することは制限が多すぎます。つまり、他の送信者が同じイベント署名を再利用できなかったことを意味します。

4
Joe

クリスアンダーソンは、フレームワーク設計ガイドラインの本で次のように述べています。

[T]彼はちょうどパターンについてです。イベント引数をクラスにパッケージ化することで、バージョン管理のセマンティクスが向上します。共通のパターンを持つことによって(sender, e)すべてのイベントの署名として簡単に学習できます。

このパターンからの逸脱を必要とする相互運用を主に含む状況があります。

2
fryguybob

使用するのは良いパターンです。そうすれば、イベントを実装するものは何でも、それを送信していたものを見つけることができます。

また、EventArgsをオーバーライドしてデータを渡すのが、最良の方法です。 EventArgsは基本クラスです。イベントを呼び出すさまざまなコントロールを見ると、それらはEventArgsをオーバーライドしており、イベントに関する詳細情報を提供します。

イベントを実行するために引数が必要ない場合でも、フレームワークの最初の実行に引数を含めず、後で追加したい場合は、以前のすべての実装を壊して、それらを書き直す必要があります。さらに、フレームワークを作成して配布しようとすると、フレームワークを使用するすべての人がリファクタリングする必要があるため、状況はさらに悪化します。

2
David Basarab

これは、時間の経過とともにイベントモデルを進化させるMicrosoftの方法のようでした。また、「新しい」アクションデリゲートとそのバリエーションを使用して別の方法でそれを行うことも許可しているようです。

1
casademora

「オブジェクト送信者」を使用すると、ハンドラーメソッドがイベントを発生させたオブジェクトに対して何かを実行することになっている場合に、1つのメソッドを複数のオブジェクトに再利用できます。

EventArgsの主な利点は、この種のイベントにサブスクライブしているすべてのプロジェクトのすべてのハンドラーの署名を変更することなく、イベント情報をリファクタリングできることです。

イベントに対処するためのよりスマートな方法は考えられません。

1
carsten

EventArgsクラスだけでは、コンテンツをインスタンス化するために派生する必要があるため、役に立ちません。これは、サブクラスを使用する必要があることを示しており、多くは.NETにすでに存在しています。悲しいことに、私は良い一般的なものを見つけることができません。

独自のEventArgsサブクラスを作成せずに、ロギングを汎用イベントに委任するとします。無意味に思えるかもしれませんが、私は既存の機能を使用するのが好きです。 Object引数を介して文字列を渡すことはできますが、それは意図された使用法に反します。 GoogleでEventArgsサブクラスの適切なリファレンスを見つけてみてください。そうすれば、乾いてしまいます。 (少なくとも私はしました。)

「EventArgs」と入力すると、文字列「EventArgs」を含むすべてのクラス(using/importsスコープ内)のリストが表示されるため、ReSharperは少し役立ちます。リストを熟読すると、文字列メンバーのない多くのクラスが表示されます。 ControlEventArgsに到達すると、Textプロパティが使用されている可能性がありますが、Windowsコントロールのすべてのオーバーヘッドがあります。 ConvertEventArgsは、データと一緒に型を渡すので便利かもしれませんが、これには、十分に文書化されておらず、本質的に型安全でもない密結合が必要です。 DataReceivedEventArgs実装はありません。 EntryWrittenEventArgsには、データのバイト配列またはStreamingContextを持つEventLogEntryが必要です。 ErrorEventArgsは、すべてのログイベントを内部でException ErrorEventsと呼んでもかまわない場合は、例外メッセージが表示されます。 FileSystemEventArgsはおそらくこれまでで最も近いものであり、2つの文字列と、実行していることがわかっている場合は0に設定できる必須のWatcherChangeTypes列挙型引数があります。 LabelEditEventArgs Windows.Forms名前空間が必要な場合は、intと文字列を使用します。 RenamedEventArgsはFileSystemEventArgsに似ていますが、文字列が追加されています。最後に、System.Runtime.InteropServicesのResolveEventArgsは単一の文字列を渡します。他にもライブラリがありますが、私は最も一般的なライブラリのいくつかに固執しました。したがって、実装に応じて、ロギングにErrorEventArgsFileSystemEventArgsまたはResolveEventArgsを使用できます。

0
CZahrobsky

すべてのイベントコンシューマーに特定のイベントパラメーターを使用するように強制したい場合があります。たとえば、ブールパラメーターを渡すセキュリティイベントです。trueは善、falseは悪です。この場合、消費者に新しいパラメータを痛感させる必要があります。つまり、消費者をそのパラメータと組み合わせる必要があります。注意してください、あなたの消費者はまだあなたのイベント発火クラスから切り離されていますが、あなたのイベントからは切り離されていません。

このシナリオは多くの場合に当てはまると思いますが、その場合、EventArgsの値は大幅に減少します。

0
Dean