web-dev-qa-db-ja.com

C#のデリゲートとインターフェイス

私は現在、代表者の使用と目的を掘り下げようとしている限り、この質問を提起したいと思いますが、同様の定式化で尋ねられた可能性があります。

デリゲートは、C++で使用される関数ポインターとして機能することを知っています。事実は、C#でインターフェイスとポリモーフィズムの代替として主に機能するかどうかです。特定のクラスのサブクラスを作成し、各サブクラスに適切なメソッドを提供できるため、デリゲートを追加で提供するものは何ですか?それらの使用を規定するケースはありますか、またはデリゲートが使用されたときにコードの保守性が改善されるだけですか?インターフェイス上での幅広い展開をお勧めしますか?

私は代表者についてのみ話しているので、彼らの役割をイベントの役割と区別したいと思います。

50
arjacsoh

はい、デリゲートは多くの点で単一メソッドインターフェイスに似ています。しかしながら:

  • CLRにはサポートが組み込まれています
  • これらのフレームワークには、マルチキャスト機能や非同期呼び出しなどのサポートがあります
  • メソッドグループ変換、ラムダ式、匿名メソッドの形式で追加のC#/ VB言語サポートがあります。
  • それらはイベントに必須です(つまり、イベントとデリゲートは一種の一致するペアです)
  • do n't作成するデリゲートインスタンスごとに、個別のクラスでインターフェイスを実装する必要があるということです。

最後のポイントは最も重要なポイントです-次のLINQ式を検討してください。

var query = collection.Where(x => x > 5)
                      .Select(x => x * x);

x > 5x * xのロジックを表現する場合、式ごとに個別のクラスを作成し、インターフェースを実装する必要があると想像してください。もちろん、言語couldは、ラムダ式から別のクラスを介したインターフェイス実装への変換を可能にするように設計されていますが、別のメソッドを作成して、それをターゲットとして委任します。また、マルチキャスト機能も失われます。

同様の思考運動として、whileforなどのループステートメントを検討してください。 gotoが得られたら、本当に必要それらですか?いや。しかし、人生ははるかに優れていますwithそれら。同じことはデリゲートにも当てはまります。実際、プロパティ、イベントなどです。これらはすべて開発を簡単にします。

71
Jon Skeet

最大の実用的の違いは、同じクラスの同じデリゲートに異なるデリゲートインスタンスを提供できることですが、インターフェイスではできません。

void delegate XYZ(int p);

interface IXyz {
    void doit(int p);
}

class One {
    // All four methods below can be used to implement the XYZ delegate
    void XYZ1(int p) {...}
    void XYZ2(int p) {...}
    void XYZ3(int p) {...}
    void XYZ4(int p) {...}
}

class Two : IXyz {
    public void doit(int p) {
        // Only this method could be used to call an implementation through an interface
    }
}
28
dasblinkenlight

差出人 インターフェイス(MSDN)の代わりにデリゲートを使用する場合

デリゲートとインターフェイスの両方により、クラス設計者は型宣言と実装を分離できます。特定のインターフェイスは、任意のクラスまたは構造体によって継承および実装できます。メソッドがデリゲートのメソッドシグネチャに適合する限り、任意のクラスのメソッドに対してデリゲートを作成できます。インターフェイス参照またはデリゲートは、インターフェイスまたはデリゲートメソッドを実装するクラスの知識を持たないオブジェクトで使用できます。これらの類似性を考えると、クラスデザイナはいつデリゲートを使用する必要があり、いつインターフェイスを使用する必要がありますか?

次の状況でデリゲートを使用します。

  • イベントデザインパターンが使用されます。
  • 静的メソッドをカプセル化することが望ましいです。
  • 呼び出し元は、メソッドを実装するオブジェクトの他のプロパティ、メソッド、またはインターフェイスにアクセスする必要はありません。
  • 簡単な構成が望まれます。
  • クラスには、メソッドの複数の実装が必要な場合があります。

次の状況でインターフェースを使用します。

  • 呼び出される可能性のある関連メソッドのグループがあります。
  • クラスには、メソッドの実装が1つだけ必要です。
  • インターフェイスを使用するクラスは、そのインターフェイスを他のインターフェイスまたはクラスタイプにキャストします。
  • 実装されるメソッドは、クラスのタイプまたはIDにリンクされます(たとえば、比較メソッド)。

デリゲートの代わりに単一メソッドインターフェイスを使用する1つの良い例は、IComparableまたは汎用バージョンIComparable(Of T)です。 IComparableはCompareToメソッドを宣言します。CompareToメソッドは、同じ型の2つのオブジェクト間のより小さい、等しい、またはより大きい関係を指定する整数を返します。 IComparableは、ソートアルゴリズムの基礎として使用できます。ソートアルゴリズムの基礎としてデリゲート比較メソッドを使用することは有効ですが、理想的ではありません。比較する機能はクラスに属し、比較アルゴリズムは実行時に変更されないため、単一メソッドのインターフェイスが理想的です。

From C#のデリゲートとインターフェイス

デリゲートとインターフェイスは、C#の2つの異なる概念ですが、共通点があります。デリゲートとインターフェイスの両方に宣言のみが含まれます。実装は、異なるプログラミングオブジェクトによって行われます。

16
Lion

デリゲートとインターフェイスは、C#の2つの異なる概念です。

インターフェイスは、オブジェクトの機能を拡張することができます。インターフェイスとそれを実装するオブジェクト間のコントラクトです。デリゲートは単なる安全なコールバックであり、一種の関数ポインタです。

4
aleroot

インターフェイスに対するデリゲートの唯一の本当の利点は

  1. デリゲートは、.Netがジェネリックをサポートする前でも、さまざまな引数タイプを処理できました。
  2. クラスは、同じ署名を共有する複数の異なるメソッドを公開するデリゲートを作成できます。デリゲートをインターフェイスに置き換えると、すべてのクラスがヘルパークラスを作成せずに各デリゲートスタイルのインターフェイスを実装する1つのメソッドを公開できますが、追加の実装ごとにヘルパークラスが必要になります。

.netがジェネリックをサポートしていなかった場合、デリゲートは必須の部分でした。なぜなら、渡すすべての異なる関数シグネチャに対して個別の非ジェネリックインターフェイスを宣言することは実行不可能だったからです。 .netが最初からジェネリックをサポートしていた場合、Reflectionを含む特定のシナリオを除いてデリゲートは不要でしたが、タイプAction<T,U>IAction<T,U>の実装にすることはおそらく最も有用でした(そのため、単に必要なコードInvokeがインターフェイスを使用できるもの)。インターフェイスベースのアプローチでは、クラスが複数のメソッドを公開するデリゲートを作成する必要がある場合は単一メソッドクラスを作成する必要がありましたが、メソッドの数が公開する署名は正確に1つです。

ちなみに、デリゲートをインターフェイスに置き換えても、汎用のCombineメソッドの作成が妨げられることはありません。実際、インターフェイスの共分散により、このようなメソッドは、多くの点で既存のDelegate.Combineよりも機能しやすくなります。 Delegate.Removeに類似したメソッドを実装するのはせいぜい面倒で迷惑ですが、Delegate.Removeの使用を必要とするイベントサブスクリプション管理以外の状況は考えられません。

1
supercat