Каково использование "абстрактного переопределения" в С#?
Просто из любопытства я попытался переопределить абстрактный метод в базовом классе и использовать метод абстрактного применения. Как показано ниже:
public abstract class FirstAbstract
{
public abstract void SomeMethod();
}
public abstract class SecondAbstract : FirstAbstract
{
public abstract override void SomeMethod();
//?? what sense does this make? no implementaion would anyway force the derived classes to implement abstract method?
}
Любопытно узнать, почему компилятор С# позволяет писать "абстрактное переопределение". Разве это не избыточно? Должна быть ошибка времени компиляции, чтобы сделать что-то вроде этого. Служит ли это для некоторых случаев использования?
Спасибо за ваш интерес.
Ответы
Ответ 1
Это полезный пример для Microsoft Docs - в основном вы можете заставить производный класс предоставить новую реализацию для метода.
public class D
{
public virtual void DoWork(int i)
{
// Original implementation.
}
}
public abstract class E : D
{
public abstract override void DoWork(int i);
}
public class F : E
{
public override void DoWork(int i)
{
// New implementation.
}
}
Если виртуальный метод объявлен абстрактным, он все еще является виртуальным для любого класса, унаследованного от абстрактного класса. Класс, унаследовавший абстрактный метод, не может получить доступ к исходной реализации метода - в предыдущем примере DoWork для класса F не может вызвать DoWork для класса D. Таким образом, абстрактный класс может заставить производные классы предоставлять новые реализации методов для виртуальных методов.,
Ответ 2
Я считаю, что это действительно полезно для обеспечения правильной реализации ToString()
в производных классах. Скажем, у вас есть абстрактный базовый класс, и вы действительно хотите, чтобы все производные классы определяли реалистичную реализацию ToString()
, потому что вы активно ее используете. Вы можете сделать это очень элегантно с помощью abstract override
:
public abstract class Base
{
public abstract override string ToString();
}
Это явный сигнал для разработчиков, что ToString()
будет использоваться в базовом классе в некотором роде (например, запись вывода пользователю). Обычно они не будут думать об определении этого переопределения.
Ответ 3
Интересно, что версия компилятора С# в Roslyn имеет в нем метод абстрактного переопределения, который я нашел достаточно странным, чтобы написать статью о:
http://ericlippert.com/2011/02/07/strange-but-legal/
Ответ 4
Представьте, что SecondAbstract
находится в середине иерархии трех классов и хочет реализовать некоторые абстрактные методы из своей базы FirstAbstract
, оставив некоторый другой метод X, который будет реализован из его дочернего ThirdAbstract
.
В этом случае SecondAbstract
вынужден украсить метод X с помощью abstract
, поскольку он не хочет предоставлять реализацию; в то же время он вынужден украсить его override
, поскольку он не определяет новый метод X, но хочет перенести ответственность за реализацию X его дочернему элементу. Следовательно, abstract override
.
В общем, понятия, моделируемые abstract
и override
, являются ортогональными. Первые силы производят классы для реализации метода, а второй признает, что метод такой же, как указано в базовом классе, а не в new
.
Таким образом:
- ни одно ключевое слово: "простой" метод
-
abstract
: производный класс должен реализовывать
-
override
only: реализация метода, определенного в базовом классе
-
abstract override
: производный класс должен реализовать метод, определенный в базовом классе
Ответ 5
Это делается потому, что в классе child вы не можете иметь метод abstract
с тем же именем, что и в базовом классе. override
сообщает компилятору, что вы переопределяете поведение базового класса.
Надеюсь, это то, что вы ищете.
Ответ 6
Если вы не объявили SomeMethod
как abstract override
в SecondAbstract
, компилятор ожидал, что этот класс будет содержать реализацию метода. С abstract override
ясно, что реализация должна быть в классе, полученном из SecondAbstract
, а не в SecondAbstract
.
Надеюсь, что это поможет...
Ответ 7
Этот шаблон проектирования известен как шаблон шаблона шаблона.
Страница Википедии о методах шаблонов
Простой пример, не относящийся к программному обеспечению: есть множество воинских частей: танки, самолеты, солдаты, линкоры и т.д. Им всем нужно реализовать некоторые общие методы, но они будут реализовывать их очень по-разному:
- Переместить()
- Атака()
- Отступление()
- Остальной()
и т.д...