Часто, в документации C#, Вы сталкиваетесь с участником, где в описании говорится что-то вроде "убедиться назвать базовый метод при переопределении этого".
Существует ли способ гарантировать во время компиляции, что каждый на самом деле вызвал основную функцию?
Вот пример: Реализация Расположить Метода
От первых строк:
Тип Располагает метод, должен высвободить все средства, которыми он владеет. Это должно также высвободить все средства, принадлежавшие его базовым типам путем вызова его родительского типа, Располагают метод.
Править
Я просматривал, и я столкнулся с этой статьей, которая кажется довольно релевантной. Это - больше маленького, чем ошибка, т.е. это имеет допустимое использование (такое как упомянутые):
Вы не можете сделать это принудительно, но вы можете сделать это через вызов типа base.Foo(bar)
. base
позволяет вам получить доступ к членам класса, от которого вы наследуете.
Вы можете обеспечить такое поведение, используя шаблонный метод. Например, представьте, что у вас есть такой код:
abstract class Animal
{
public virtual void Speak()
{
Console.WriteLine("I'm an animal.");
}
}
class Dog : Animal
{
public override void Speak()
{
base.Speak();
Console.WriteLine("I'm a dog.");
}
}
Проблема здесь в том, что любой класс, наследующий от Animal
, должен вызвать base.Speak();
, чтобы обеспечить выполнение базового поведения. Вы можете автоматически обеспечить это, используя следующий (немного другой) подход:
abstract class Animal
{
public void Speak()
{
Console.WriteLine("I'm an animal.");
DoSpeak();
}
protected abstract void DoSpeak();
}
class Dog : Animal
{
protected override void DoSpeak()
{
Console.WriteLine("I'm a dog.");
}
}
В этом случае клиенты по-прежнему видят только полиморфный метод Speak
, но поведение Animal.Speak
гарантированно выполняется. Проблема в том, что если у вас есть дальнейшее наследование (например, class Dachsund : Dog
), вам придется создать еще один абстрактный метод, если вы хотите, чтобы Dog.Speak
гарантированно выполнялся.
Вы можете вызвать его так:
public override void MyFunction()
{
// do dome stuff
SomeStuff();
// call the base implementation
base.MyFunction();
}
Но если вы спрашиваете, можно ли его "проверить" во время компиляции - нет.
Вероятно, вы можете использовать инструмент анализа зависимостей, такой как NDepend, для создания правил, проверяющих, выполняется ли это, и запустить эти правила как часть компиляции, но я не думаю, что вы можете сделать это из самого компилятора.
Обычным шаблоном для одного уровня наследования является предоставление невиртуального метода шаблона с виртуальной точкой расширения.
protected virtual void ExtensionPoint () { }
public void TemplateMethod () {
ExtensionPoint();
ThisWillAlwaysGetCalled();
}
Если все вызовы операции вызывают метод шаблона, то будет вызвано любое переопределение точки расширения вместе с кодом в методе шаблона, который всегда будет вызываться.