Использование интерфейсов на абстрактных классах в C # - PullRequest
20 голосов
/ 26 марта 2009

Я изучаю C # из C ++ и наткнулся на стену.

У меня есть абстрактный класс 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 ()).

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

Ответы [ 4 ]

42 голосов
/ 26 марта 2009

Вы столкнулись с проблемой, потому что вы использовали явная реализация интерфейса (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 в двух случаях:

  • У вас есть класс, который должен реализовывать два интерфейса, каждый из которых содержит член, имеющий идентичное имя / подпись для другого члена в другом интерфейсе.
  • Вы хотите, чтобы заставили клиентов зависеть не от деталей реализации вашего класса, а от интерфейса, который реализуется вашим классом. (Некоторые считают это хорошей практикой.)
8 голосов
/ 26 марта 2009

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

public abstract class AbstractWidget : IDoesCoolThings 
{
    public void DoCool()
    { 
        Console.Write("I did something cool."); 
    }
}
7 голосов
/ 26 марта 2009

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

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

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

Читать это:

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

1 голос
/ 30 января 2013

Вы должны сделать это так:

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();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...