Вызов виртуальных функций из конструктора и макетирование

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

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