web-dev-qa-db-ja.com

C#で拡張メソッドとのインターフェイスの代わりに抽象クラスを使用するのはいつですか?

「抽象クラス」と「インターフェース」は類似した概念であり、インターフェースの方が2つのうち抽象的なものです。 1つの差別化要因は、抽象クラスが、必要に応じて派生クラスのメソッド実装を提供することです。ただし、C#では、最近の拡張メソッドの導入により、この差別化要因が軽減され、インターフェイスメソッドに実装を提供できるようになりました。別の差別化要因は、クラスは1つの抽象クラスしか継承できない(つまり、複数の継承がない)ことですが、複数のインターフェースを実装できます。これにより、インターフェースの制限が緩和され、柔軟性が高まります。 つまり、C#では、拡張メソッドのあるインターフェイスではなく、いつ抽象クラスを使用する必要がありますか?

インターフェース+拡張メソッドモデルの注目すべき例はLINQです。この場合、クエリ機能は、多数の拡張メソッドを介してIEnumerableを実装するすべての型に提供されます。

70
Gulshan

クラスの一部を実装する必要がある場合。私が使用した最良の例は template method パターンです。

public abstract class SomethingDoer
{
    public void Do()
    {
        this.DoThis();
        this.DoThat();
    }

    protected abstract void DoThis();
    protected abstract void DoThat();
}

したがって、Do()が呼び出されたときに実行されるステップを、それらの実装方法の詳細を知らなくても定義できます。派生クラスは、Do()メソッドではなく、抽象メソッドを実装する必要があります。

拡張メソッドは、方程式の「クラスの一部でなければならない」部分を必ずしも満たす必要はありません。さらに、iirc、拡張メソッドは、スコープ内でパブリック以外にすることはできません。

edit

この質問は、私が当初信じていたよりも興味深いものです。さらに詳しく調べてみると、Jon Skeet 回答済み SOインターフェース+拡張メソッドの使用に賛成です。また、 潜在的なマイナス面 についての質問です。このように設計されたオブジェクト階層に対してリフレクションを使用しています。

個人的に、私は現在一般的な慣行を変更することの利点を理解するのに苦労していますが、それを行うことの欠点はほとんどないかまったくありません。

ユーティリティクラスを使用して、この方法を多くの言語でプログラミングできることに注意してください。拡張機能は、メソッドがクラスに属しているように見せるための構文糖を提供します。

63
Steven Evers

私は、私が(少なくとも作成されていない)抽象クラスを何年も使用していないことに気づきました。

抽象クラスは、インターフェースと実装の間のやや奇妙な獣です。抽象クラスには、私のスパイダーセンスを刺激する何かがあります。私は、インターフェイスの背後にある実装を何らかの方法で「公開」してはなりません(または、何らかの結びつきを作ってはいけません)。

インターフェイスを実装するクラス間で共通の動作が必要な場合でも、抽象クラスではなく、独立したヘルパークラスを使用します。

インターフェイスに行きます。

3
Maglob

私見、ここには概念の混合があると思います。

クラスは特定の種類の継承を使用しますが、インターフェイスは別の種類の継承を使用します。

どちらの種類の継承も重要かつ有用であり、それぞれに長所と短所があります。

最初から始めましょう。

インターフェースのあるストーリーは、C++で昔から始まっています。 1980年代の半ば、C++が開発されたとき、別の種類の型としてのインターフェイスの概念はまだ実現されていませんでした(それは間に合うでしょう)。

C++には、実装の継承と呼ばれる、クラスで使用される一種の継承しかありませんでした。

GoF Bookの推奨事項を適用できるようにするには、「実装ではなく、インターフェース用にプログラミングする」ために、C++は抽象クラスと複数の実装継承をサポートし、C#のインターフェースが実行できる(そして便利です)ことができるようになりました。 。

C#では、新しい種類の型、インターフェイス、および新しい種類の継承であるインターフェイスの継承が導入され、「実装ではなくインターフェイス用にプログラムする」ための少なくとも2つの異なる方法が提供されていますが、重要な注意点が1つあります:C#のみインターフェースの継承による多重継承をサポートします(実装の継承ではサポートしません)。

したがって、C#のインターフェイスの背後にあるアーキテクチャ上の理由は、GoFの推奨事項です。

これがお役に立てば幸いです。

親切に、ガストン

拡張メソッドをインターフェースに適用すると、共通のインターフェースのみを共有する可能性のあるクラス間で共通の動作を適用するのに役立ちます。このようなクラスはすでに存在していて、他の方法で拡張機能に閉じている場合があります。

新しいデザインでは、インターフェイスでの拡張メソッドの使用を推奨します。タイプの階層の場合、拡張メソッドは、変更のために階層全体を開かなくても動作を拡張する手段を提供します。

ただし、拡張メソッドはプライベート実装にアクセスできないため、階層の最上位で、パブリックインターフェイスの背後にプライベート実装をカプセル化する必要がある場合は、抽象クラスが唯一の方法です。

1
Ed James

C#では多重継承はサポートされていないと思います。そのため、C#でインターフェイスの概念が導入されています。

抽象クラスの場合、多重継承もサポートされていません。したがって、抽象クラスまたはインターフェースを使用するかどうかを決定するのは簡単です。

0
Beginner