Какая польза от "абстрактного переопределения" в C#?

Просто из любопытства я попытался переопределить абстрактный метод в базовом классе, а метод - абстрактную реализацию. Как показано ниже:

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?
}

Любопытно узнать, почему компилятор C# позволяет писать "абстрактное переопределение". Разве это не избыточно? Должно быть ошибка времени компиляции, чтобы сделать что-то вроде этого. Это служит некоторому варианту использования?

Спасибо за ваш интерес.

7 ответов

Решение

Для MSDN есть полезный пример - в основном вы можете заставить производный класс предоставить новую реализацию для метода.

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

Я считаю, что это действительно полезно для обеспечения надлежащего ToString() реализация в производных классах. Допустим, у вас есть абстрактный базовый класс, и вы действительно хотите, чтобы все производные классы определяли значения ToString() реализация, потому что вы активно используете его. Вы можете сделать это очень элегантно с abstract override:

public abstract class Base
{
    public abstract override string ToString();
}

Это явный сигнал для разработчиков, что ToString() будет использоваться в базовом классе в некотором роде (например, запись вывода пользователю). Обычно они не думают об определении этого переопределения.

Интересно, что в версии Roslyn для компилятора C# есть абстрактный метод переопределения, который я нашел достаточно странным, чтобы написать статью о:

http://ericlippert.com/2011/02/07/strange-but-legal/

Представь это SecondAbstract находится в середине иерархии трех классов, и он хочет реализовать некоторые абстрактные методы из своей базы FirstAbstract оставляя некоторый другой метод X, который будет реализован от его потомка ThirdAbstract,

В этом случае, SecondAbstract вынужден украсить метод X abstract поскольку он не хочет предоставлять реализацию; в то же время, он вынужден украшать его override поскольку он не определяет новый метод X, но хочет перенести ответственность за реализацию X на его дочерний элемент. Следовательно, abstract override,

В общем, концепции смоделированы abstract а также override ортогональны. Первая заставляет производные классы реализовывать метод, а вторая признает, что метод такой же, как указано в базовом классе, а не new один.

Следовательно:

  • ни одно из ключевых слов: "простой" метод
  • abstract только: производный класс должен реализовывать
  • override только: реализация метода, определенного в базовом классе
  • abstract override: производный класс должен реализовывать метод, определенный в базовом классе

Это сделано потому, что в детском классе вы не можете иметь abstract метод с тем же именем, что и в базовом классе. override сообщает компилятору, что вы переопределяете поведение базового класса.

Надеюсь, это то, что вы ищете.

Если вы не заявили SomeMethod как abstract override в SecondAbstractкомпилятор будет ожидать, что этот класс будет содержать реализацию метода. С abstract override ясно, что реализация должна быть в классе, производном от SecondAbstract и не в SecondAbstract сам.

Надеюсь это поможет...

Этот шаблон проектирования известен как шаблонный шаблон.

Страница Википедии о методах шаблонов

Простой, не программный пример: существует множество военных подразделений: танки, самолеты, солдаты, линейные корабли и т. Д. Все они должны реализовать некоторые общие методы, но будут реализовывать их совершенно по-разному:

  • Переехать()
  • Атака()
  • Отступление ()
  • Остальное()

так далее...

Другие вопросы по тегам