Вызов виртуальных функций из конструктора и макетирование
Рекомендуется не вызывать виртуальные функции из конструктора базовых классов (предупреждение отображается в FxCop или Sonar), однако как насчет классов, которые не предназначены для использования в качестве базовых классов, но имеют виртуальные методы для имитации. Это тот случай, когда я должен использовать файл GlobalSuppressions или есть способ смоделировать метод, который вызывается в конструкторе, не будучи виртуальным?
Вот код для пояснения:
public class MyClass
{
public MyClass()
{
MyVirtualMethod();
}
private virtual void MyVirtualMethod() { }
}
MyVirtualMethod является виртуальным только для насмешек.
1 ответ
Причина, по которой вы не хотите вызывать виртуальные методы в конструкторе, заключается в том, что они не будут вызываться из конструктора базового класса. Другими словами, если вы создаете экземпляр производного класса, вам нужно явно вызвать реализацию виртуального метода для производных классов в его конструкторе.
Таким образом, ваш виртуальный метод не будет виртуальным.
Ниже приведен пример из C++ FAQ, транскодированного в C#.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace VirtualMethodCalledFromConstructor
{
class Program
{
static void Main(string[] args)
{
Derived d = new Derived();
Console.ReadLine();
}
}
public class Base
{
public Base()
{
Console.WriteLine("Base::Base()");
virt();
}
public virtual void virt()
{
Console.WriteLine("Base::virt()");
}
}
public class Derived : Base
{
public Derived()
{
Console.WriteLine("Derived::Derived()");
virt();
}
public virtual void virt()
{
Console.WriteLine("Derived::virt()");
}
}
}
Это приводит к следующему выводу в консоли:
Base::Base()
Base::virt() // <--- not Derived::virt()
Derived::Derived()
Derived::virt()
Обратите внимание, что Derived::virt() вызывается только потому, что конструктор Derived явно вызвал его.