web-dev-qa-db-ja.com

C#の抽象クラスでインターフェイスを使用する

私はC++から来るC#を学んでいて、壁にぶつかりました。

抽象クラスAbstractWidget、インターフェイスIDoesCoolThings、およびRealWidgetと呼ばれるAbstractWidgetから派生したクラスがあります。

public interface IDoesCoolThings
{
    void DoCool();
}

public abstract class AbstractWidget : IDoesCoolThings
{
    void IDoesCoolThings.DoCool()
    {
        Console.Write("I did something cool.");
    }
}

public class RealWidget : AbstractWidget
{

}

RealWidgetオブジェクトをインスタンス化してDoCool()を呼び出すと、コンパイラーは次のようなエラーを表示します。

「RealWidget」には「DoCool」の定義が含まれていません

RealWidgetオブジェクトをIDoesCoolThingsにキャストすると、呼び出しは機能しますが、それは不要のようで、ポリモーフィズムも失われます(RealWidget.DoCool()を定義しても、AbstractWidget.DoCool()は常に呼び出されます)。

解決策は簡単だと思いますが、いろいろ試してみましたが、一生理解できません。

20
JubJub

明示的なインターフェースの実装を使用したため、問題が発生しています(EII)。メンバーが明示的に実装されている場合、クラスインスタンスを介してアクセスすることはできません。インターフェイスのインスタンスを介してのみアクセスできます。あなたの例では、インスタンスをIDoesCoolThingsにキャストしない限り、DoCool()を呼び出すことができないのはそのためです。

解決策は、DoCool()を公開し、明示的なインターフェイスの実装を削除することです。

public abstract class AbstractWidget : IDoesCoolThings
{
    public void DoCool()      // DoCool() is part of the abstract class implementation.
    {
        Console.Write("I did something cool.");
    }
}

// ...

var rw = new RealWidget();
rw.DoCool();                  // Works!

一般に、EIIは次の2つの場合に使用します。

  • 2つのインターフェースを実装する必要があるクラスがあり、それぞれに、他のインターフェースの別のメンバーと同じ名前/署名を持つメンバーが含まれています。
  • クライアントをforceして、クラスの実装の詳細に依存するのではなく、クラスによって実装されているインターフェイスに依存させたいと考えています。 (これは一部の人にとっては良い習慣だと考えられています。)
42
John Feminella

宣言を次のように変更します。

public abstract class AbstractWidget : IDoesCoolThings 
{
    public void DoCool()
    { 
        Console.Write("I did something cool."); 
    }
}
8
Mitch Wheat

暗黙的な実装イ​​ンターフェースを選択した場合、インターフェースを実装する方法は、明示的な実装void IDoesCoolThings.DoCool()です。

public abstract class AbstractWidget : IDoesCoolThings
{
    public void DoCool()
    {
        Console.Write("I did something cool.");
    }
}

その後、それは動作します。

これを読む :

C#インターフェイス。暗黙的な実装と明示的な実装

7
J.W.

あなたはこのようにそれをするべきです:

public interface IDoesCoolThings 
{
   void DoCool();
}

public abstract class AbstractWidget 
{
   public void DoCool()
   {
      Console.WriteLine("I did something cool.");
   }
}

public class Widget : AbstractWidget, IDoesCoolThings 
{
}

使用法:

var widget = new Widget();
widget.DoCool();
1
Toffee