.NET プラットフォームを初めて使用する開発者は、多くの場合、 delegates
に基づくデザインと、 events
に基づくデザインを決定するときに苦労します。 デリゲートまたはイベントの選択は、多くの場合、2 つの言語機能が似ているため、困難です。 イベントは、デリゲートの言語サポートを使用して構築されます。 イベント ハンドラー宣言は、デリゲート型を宣言します。
どちらも遅延バインディング シナリオを提供します。実行時にのみ認識されるメソッドを呼び出してコンポーネントが通信するシナリオを可能にします。 これらはどちらも、単一および複数のサブスクライバーメソッドをサポートします。 これらの用語は、単一キャストおよびマルチキャストサポートと呼ばれる場合があります。 どちらもハンドラーを追加および削除するための同様の構文をサポートしています。 最後に、イベントを発生させ、デリゲートを呼び出すと、まったく同じメソッド呼び出し構文が使用されます。 どちらも、Invoke()
演算子で使用するために同じ?.
メソッド構文をサポートしています。
これらすべての類似点により、使用するタイミングを判断する際に問題が発生しやすくなります。
イベントを聞くことはオプションです
使用する言語機能を決定する際に最も重要な考慮事項は、サブスクライバーがアタッチされている必要があるかどうかです。 コードでサブスクライバーから提供されたコードを呼び出す必要がある場合は、コールバックを実装する必要があるときにデリゲートに基づくデザインを使用する必要があります。 サブスクライバーを呼び出さずにコードのすべての作業を完了できる場合は、イベントに基づく設計を使用する必要があります。
このセクションで構築した例を考えてみましょう。 要素を適切に並べ替えるには、 List.Sort()
を使用してビルドしたコードに比較子関数を指定する必要があります。 返す要素を決定するには、LINQ クエリにデリゲートを指定する必要があります。 いずれもデリゲートで作成したデザインを使用しています。
Progress
イベントについて考えてみましょう。 タスクの進行状況を報告します。 リスナーがあるかどうかに関係なく、タスクは続行されます。
FileSearcher
も別の例です。 イベント購読者がアタッチされていない場合でも、目的のすべてのファイルを検索し発見します。 イベントをリッスンしているサブスクライバーがいない場合でも、UX コントロールは引き続き正しく機能します。 どちらもイベントに基づくデザインを使用します。
戻り値でデリゲートが必要になる
もう 1 つの考慮事項は、デリゲート メソッドに必要なメソッド プロトタイプです。 ご覧のとおり、イベントに使用されるデリゲートにはすべて戻り値の型 void が与えられます。 イベント引数オブジェクトのプロパティを変更してイベント ソースに情報を返すイベント ハンドラーを作成するイディオムがあります。 これらのイディオムは機能しますが、メソッドから値を返すほど自然ではありません。
多くの場合、これら 2 つのヒューリスティックが存在する可能性があることに注意してください。デリゲート メソッドが値を返すと、何らかの方法でアルゴリズムに影響します。
イベントにプライベート呼び出しがある
イベントが含まれるクラス以外のクラスは、イベント リスナーの追加と削除のみを行うことができます。イベントを呼び出すことができるのは、イベントを含むクラスだけです。 イベントは、一般にパブリック クラスのメンバーです。 これに対して、デリゲートは多くの場合、パラメーターとして渡され、プライベート クラス メンバーとして格納されます (すべて格納されている場合)。
多くの場合、イベント リスナーの有効期間は長くなります
イベント リスナーの有効期間が長くなることは、やや弱い正当化の理由です。 ただし、イベント ソースが長期間にわたってイベントを発生させている場合は、イベント ベースのデザインの方が自然である場合があります。 多くのシステム上の UX コントロールのイベント ベースの設計の例を確認できます。 イベントをサブスクライブすると、イベント ソースはプログラムの有効期間中にイベントを発生させることができます。 (イベントが不要になった場合は、イベントのサブスクライブを解除できます)。
デリゲートがメソッドの引数として使用され、そのメソッドが戻った後にデリゲートが使用されない多くのデリゲート ベースのデザインとは対照的です。
慎重に評価する
上記の考慮事項は厳格な規則ではありません。 代わりに、特定の使用に最適な選択肢を決定するのに役立つガイダンスを表します。 これらは似ているので、両方のプロトタイプを作成して、どちらで作業するのが自然かを検討することもできます。 どちらも遅延バインディング シナリオを適切に処理します。 最適なデザインを伝える機能を使用します。
.NET