Предотвращение переопределения метода в С#

Как предотвратить переопределение метода в производном классе?

В Java я мог бы сделать это, используя модификатор final для метода, который я хочу предотвратить переопределением.

Как добиться того же результата в С#? Я знаю использование sealed, но, видимо, я могу использовать его только с ключевым словом override?

class A
{
    public void methodA()
    {
        // Code.
    }

    public virtual void methodB()
    {
        // Code.
    }
}

class B : A
{
    sealed override public void methodB()
    {
        // Code.
    } 
}

Итак, в приведенном выше примере я могу предотвратить переопределение methodB() любыми классами, происходящими из класса B, но как я могу предотвратить класс B от переопределения methodB() в первую очередь?

Обновление. Я пропустил ключевое слово virtual в объявлении methodB() в классе A, когда я разместил этот вопрос. Исправлено.

Ответ 1

Вам ничего не нужно делать. Модификатор virtual указывает, что метод может быть переопределен. Опущение это означает, что метод является "окончательным".

В частности, метод должен быть virtual, abstract или override для его переопределения.

Использование ключевого слова new позволяет скрывать метод базового класса, но он все равно не будет переопределять его, т.е. при вызове A.methodB() вы получите версию базового класса, но если вы вызовете B.methodB(), вы получить новую версию.

Ответ 2

Как вы упомянули, вы можете предотвратить дальнейшее переопределение метода MethodB в классе B с помощью sealed с override

class B : A
{
    public sealed override void methodB()
    {
        Console.WriteLine("Class C cannot override this method now");
    }
}

Использование модификатора sealed вместе с override предотвращает последующее переопределение производного класса.

Если вы не хотите, чтобы methodB в классе A был переопределен любыми дочерними классами, не отмечайте этот метод virtual. Просто удалите его. virtual ключевое слово разрешает переопределять метод в дочерних классах

public void methodA()
{       
}

Используйте ключевое слово sealed на своих классах, чтобы предотвратить дальнейшее переопределение класса

Ответ 3

В С# функция, не отмеченная virtual (которая также включает в себя переопределения виртуальных функций), эффективно закрывается и не может быть переопределена. Таким образом, ваш пример кода фактически не будет компилироваться, потому что ключевое слово переопределения недействительно, если только в методе, отмеченном virtual, не указана одна и та же подпись в базовом классе.

Если A.methodB() были помечены как виртуальные, то вы можете переопределить метод из A, но не допускать его переопределения в классах, полученных более косвенно, используя ключевое слово sealed точно так, как вы показали.

Одна вещь, о которой следует помнить, заключается в том, что, хотя переопределение метода можно предотвратить, метод скрытия не может. Учитывая ваше текущее определение класса A, следующее определение класса B является законным, и вы ничего не можете с этим сделать:

class B:A
 {
      public new void methodB()
            {
                    //code
            } 
  }

Ключевое слово new в основном "разбивает" иерархию наследования/переопределения, поскольку оно относится к этому методу; любая ссылка на класс B, рассматриваемая как класс B (или любой другой производный тип), будет использовать реализацию из класса B и игнорировать одну из класса A, если только реализация B специально не обратится к ней. Однако, если вы должны рассматривать экземпляр класса B как класс A (путем его литья или передачи его как параметра), тогда "новая" реализация игнорируется.

Это отличается от переопределения, когда класс B, который рассматривается как класс A и по-настоящему переопределяет виртуальный метод B, все равно будет использовать переопределение класса B метода. Также поймите, что скрывается метод (хотя вы получите предупреждение компилятора); если вы объявляете метод с той же сигнатурой в производном классе и не указываете ни новое, ни переопределение, метод базового класса будет скрыт.

Ответ 4

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

Чтобы предотвратить переопределение метода базового класса, просто не указывайте его как виртуальный. В приведенном примере класс B не может переопределить methodB, потому что methodB не был помечен как виртуальный в исходном классе.

это скомпилирует:

class A
{
    public virtual void methodA()
    {
        //code
    }
    public virtual void methodB()
    {
        //code
    }
}
class B:A
{
    public override void methodB()
    {
        //code
    } 
}

это не будет:

class A
{
    public void methodA()
    {
        //code
    }
    public void methodB()
    {
        //code
    }
}
class B:A
{
    public override void methodB()
    {
        //code
    } 
}

РЕДАКТИРОВАНО: уточнено и исправлено исходное выражение о закрытом ключевом слове