Наследование интерфейса С# для абстрактного класса
Предположим, что у меня есть интерфейс, как определено ниже:
public interface IFunctionality
{
void Method();
}
и я реализую этот интерфейс для абстрактного класса, как показано ниже:
public abstract class AbstractFunctionality: IFunctionality
{
public void Method()
{
Console.WriteLine("Abstract stuff" + "\n");
}
}
снова у меня есть конкретный класс, который наследует от абстрактного класса, как показано ниже:
public class ConcreteFunctionality: AbstractFunctionality
{
public void Method()
{
Console.WriteLine("Concrete stuff" + "\n");
}
}
Теперь у меня есть следующий код,
ConcreteFunctionality mostDerived = new ConcreteFunctionality();
AbstractFunctionality baseInst = mostDerived;
IFunctionality interfaceInst = mostDerived;
mostDerived.Method();
baseInst.Method();
interfaceInst.Method();
Результат, который я получаю после выполнения этого материала, выглядит следующим образом.
Concrete stuff
Abstract stuff
Abstract stuff
Но то, что я ожидал, что вывод будет "Concrete Stuff" во всех трех случаях, поскольку то, что я здесь делаю, присваивает ссылку ConcreteFunctionality
переменным типа AbstractFunctionality
и IFunctionality
.
Что происходит внутри страны. Просьба уточнить.
Ответы
Ответ 1
Здесь:
public class ConreteFunctionality:AbstractFunctionality
{
public void Method()
{
Console.WriteLine("Concrete stuff" + "\n");
}
}
... вы не переопределяете существующий метод. Вы создаете новый метод, который скрывает существующий. (Вы также должны получить предупреждение, предлагающее использовать модификатор new
, если вы действительно этого хотите.) Интерфейс был реализован в AbstractFunctionality
, поэтому таблица сопоставления интерфейса ссылается на метод в этом классе.
Теперь, если вы переопределите интерфейс:
public class ConcreteFunctionality : AbstractFunctionality, IFunctionality
... тогда сопоставление интерфейса будет ссылаться на метод в ConcreteFunctionality
, и вы получите поведение, которое вы ожидаете для вызова через интерфейс (т.е. ваш третий вызов), но вы все равно получите реализацию в AbstractFunctionality
для вашего второго вызова.
Было бы более чистым и более безопасным, чтобы сделать метод в AbstractFunctionality
виртуальным и переопределить его в ConcreteFunctionality
. Таким образом, он будет использовать реализацию ConcreteFunctionality
во всех случаях.
Ответ 2
Вам нужно определить классы как:
public abstract class AbstractFunctionality:IFunctionality
{
public virtual void Method()
{
Console.WriteLine("Abstract stuff" + "\n");
}
}
public class ConreteFunctionality:AbstractFunctionality
{
public override void Method()
{
Console.WriteLine("Concrete stuff" + "\n");
}
}
Поскольку вы не переопределили метод() в ConreteFunctionality, среда времени выполнения выполняет метод(), связанный с объектом AbstractFunctionality, поскольку здесь он не может применять динамический полиморфизм. Введение virtual
и override
заставляет среду выполнения выполнять метод переопределения в дочернем классе.
Ответ 3
Вам не хватает ключевых слов virtual
и override
. Без этого вы не получите виртуальных функций.
Вы можете пометить Method
в AbstractFunctionality как virtual
и пометить Method
в ConreteFunctionality
как override
. Как показал михир.
Аналогичные проблемы решаются в Почему методы интерфейса С# не объявлены абстрактными или виртуальными?