I will try to explain this concept with a demonstration of calling virtual method in base class constructor
Here is some brief information about the below program
- Created a base class "TestBase" and a derived class "TestDerived "
- In base class added one property "BaseName" and virtual method "GetName()"
- And in base class constructor initialized "BaseName" property and then called GetName() virtual method
- In derived class added one property "DerivedName" and overridden "GetName()" method
- In derived class constructor initialized "DerivedName" property
- And In Main method created object of TestDerived
- using System;
- namespace BestPractices
- {
- static class Program
- {
- private static void Main()
- {
- TestDerived tb = new TestDerived("John");
- Console.ReadLine();
- }
- }
-
- public class TestBase
- {
- public string BaseName { get; set; }
- public TestBase(string name)
- {
- this.BaseName = name;
- GetName();
- }
- public virtual void GetName()
- {
- Console.WriteLine("Base GetName called:" + BaseName);
- }
- }
-
- public class TestDerived : TestBase
- {
- public string DerivedName { get; set; }
-
- public TestDerived(string name):base(name)
- {
- this.DerivedName = name;
- }
- public override void GetName()
- {
- Console.WriteLine("Derived GetName called:" + DerivedName);
- }
- }
- }
How will the above program execute?
- In the main method I have created a object of "TestDerived" class which is derived class of "TestBase". As per the constructor execution when we create object of derived class, first the base class constructor will get executed and then derived class constructor. So in our case "TestBase" constructor will get executed first and in TestBase constructor we have initialized BaseName property and then called "GetName()" name method.
- As per the above point it feels that execution of TestBase constructor is straightforward and GetName method of base class will get executed and it will print output as below:
Base GetName called::John
But surprisingly the above output is incorrect and the correct output is:
Derived GetName called
- The reason for the above output is, as per the rule of virtual method execution, when we override virtual method in derived class and create derived class object then derived class method will get executed. In the above example we have overridden GetName method in TestDerived class. So when TestBase class constructor calls GetName method, GetName method of derived class(TestDerived) will get executed. GetName method in derived class prints DerivedName, but as Derived class constructor is not executed yet, so DerivedName property will remain uninitialized and it will print the output as "Derived GetName called:"
- The conclusion of the above demo is that calling a virtual method in base class constructor can cause inconsistent behavior of application, as you are calling derived class method before initializing all the properties of derived class. In our case GetName method of derived class is getting executed before initializing "DerivedName" property
I will try to explain what harm can be caused by calling virtual method in base class constructor
Brief information about the below program
- Created one base class TestBadPracticeBase, and added one field strBaseList which is List of string and added on virtual method PrintList and inside TestBadPracticeBase constructor initialized strBaseList and called PrintList() virtual method
- Created one Derived class TestBadPracticeDerived and added one field strList which is List of string. Inside TestBadPracticeDerived constructor initialized strList. Also overridden base class virtual method PrintList()
- Inside main method created object of TestBadPracticeDerived class
- using System;
- using System.Collections.Generic;
- namespace TestBadPractices
- {
- static class Program
- {
- private static void Main()
- {
- TestBadPracticeDerived tb = new TestBadPracticeDerived();
- Console.ReadLine();
- }
- }
- public class TestBadPracticeBase
- {
- public readonly List<String> strBaseList;
- public TestBadPracticeBase()
- {
- strBaseList = new List<string> { "test1", "test2" };
- PrintList();
- }
- public virtual void PrintList()
- {
- Console.WriteLine("Base List:");
- foreach (var item in strBaseList)
- {
- Console.WriteLine(item);
- }
- }
- }
-
- public class TestBadPracticeDerived : TestBadPracticeBase
- {
- public string DerivedName { get; set; }
- public readonly List<String> strList;
- public TestBadPracticeDerived()
- {
- strList = new List<string> { "test1", "test2" };
- }
- public override void PrintList()
- {
- Console.WriteLine("Derived List:");
- foreach (var item in strList)
- {
- Console.WriteLine(item);
- }
- }
- }
- }
-
Above program will throw the following exeception:
Unhandled Exception - System.NullReferenceException - Object reference not set to an instance of an object.
Explanation
As explained in the first example, as per the sequence of constructor execution, base class constructor will get executed first. In our case TestBadPracticeBase constructor will get executed first. Inside TestBadPracticeBase constructor we have called virtual method PrintList and as we are creating object of derived class derived class overridden method will get executed so here PrintList method of derived class will get executed. Inside derived class PrintList method we are iterating through strList but strList list is not initialized because derived class constructor is not executed yet. So PrintList method will throw an exception.
Unhandled Exception - System.NullReferenceException - Object reference not set to an instance of an object.
The above two programs prove that calling virtual method inside base class constructor is a bad practice as it can produce inconsistent results.