Использование интерфейсов для абстрактных классов в С#

Я изучаю С#, исходящий из С++, и столкнулся с стеной.

У меня есть абстрактный класс AbstractWidget, интерфейс IDoesCoolThings и класс, который происходит из AbstractWidget под названием RealWidget:

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, а затем вызов будет работать, но это кажется ненужным, и я также теряю полиморфизм (AbstractWidget.DoCool() всегда будет вызываться, даже если я определяю RealWidget.DoCool()).

Я предполагаю, что решение прост, но я пробовал разные вещи, и для меня жизнь не может понять этого.

+20
источник поделиться
4 ответа

У вас возникла проблема, потому что вы использовали явную реализацию интерфейса (EII). Когда элемент явно реализован, к нему нельзя получить доступ через экземпляр класса - только через экземпляр интерфейса. В вашем примере, почему вы не можете вызвать DoCool(), если вы не нарисуете свой экземпляр на IDoesCoolThings.

Решение состоит в том, чтобы сделать 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 в двух случаях:

  • У вас есть класс, который должен реализовывать два интерфейса, каждый из которых содержит член, который имеет идентичное имя/подпись другому члену в другом интерфейсе.
  • Вы хотите заставить клиентов не зависеть от деталей реализации вашего класса, а скорее от интерфейса, который реализуется вашим классом. (Это считается хорошей практикой для некоторых.)
+41
источник

Измените свою декларацию на:

public abstract class AbstractWidget : IDoesCoolThings 
{
    public void DoCool()
    { 
        Console.Write("I did something cool."); 
    }
}
+8
источник

Способ реализации интерфейса - это явное реализация void IDoesCoolThings.DoCool(), если вы выберете неявный интерфейс реализации.

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

Тогда он будет работать.

Прочтите это:

Интерфейсы С#. Неявная реализация по сравнению с явной реализацией

+7
источник

Вы должны сделать это следующим образом:

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
источник

Посмотрите другие вопросы по меткам или Задайте вопрос