Использование интерфейсов для абстрактных классов в С#
Я изучаю С#, исходящий из С++, и столкнулся с стеной.
У меня есть абстрактный класс 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()).
Я предполагаю, что решение прост, но я пробовал разные вещи, и для меня жизнь не может понять этого.
Ответы
Ответ 1
У вас возникла проблема, потому что вы использовали явную реализацию интерфейса (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 в двух случаях:
- У вас есть класс, который должен реализовывать два интерфейса, каждый из которых содержит член, который имеет идентичное имя/подпись другому члену в другом интерфейсе.
- Вы хотите заставить клиентов не зависеть от деталей реализации вашего класса, а скорее от интерфейса, который реализуется вашим классом. (Это считается хорошей практикой для некоторых.)
Ответ 2
Измените свою декларацию на:
public abstract class AbstractWidget : IDoesCoolThings
{
public void DoCool()
{
Console.Write("I did something cool.");
}
}
Ответ 3
Способ реализации интерфейса - это явное реализация void IDoesCoolThings.DoCool(), если вы выберете неявный интерфейс реализации.
public abstract class AbstractWidget : IDoesCoolThings
{
public void DoCool()
{
Console.Write("I did something cool.");
}
}
Тогда он будет работать.
Прочтите это:
Интерфейсы С#. Неявная реализация по сравнению с явной реализацией
Ответ 4
Вы должны сделать это следующим образом:
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();