Wednesday, October 01, 2008

Avoid invoking a virtual method in a constructor

You should be very careful when invoking a virtual method in the constructor of a class that is not sealed.

Reason: when the virtual method is overriden in a derived class, this method will be invoked even before the constructor of the derived class has been invoked! This probably was not anticipated by the developer of the derived class!

Take for instance this example:

   1: abstract class Base
   2: {
   3:     public Base() // This constructor calls a virtual method
   4:     {
   5:         Initialize();
   6:     }
   7:  
   8:     protected abstract void Initialize();
   9: }
  10:  
  11: class Derived : Base
  12: {
  13:     FileStream m_File;
  14:  
  15:     public Derived()
  16:     {
  17:         m_File = new FileStream(@"c:\temp\test.txt", FileMode.Open);
  18:     }
  19:  
  20:     protected override void Initialize()
  21:     {
  22:         MessageBox.Show(m_File.Length.ToString());    // NullReferenceException! m_File has not been constructed yet!
  23:     }
  24: }

When an instance of Derived is created, first the constructor of the base class is called. This will result in Derived.Initialize() being called before the constructor of Derived has executed!

Because this is very contra-intuitive, it is best not to invoke virtual methods from a constructor altogether. Except when the class is sealed of course, because then there can be no derived class.

2 comments:

Steven said...

Did you know that FxCop has a rule for this?

Luke Puplett said...

Visual Studio 2008 Team Thingy can also trace call paths and point out more complicated routes to virtuals.

And watch out for state changes raising events via virtual OnSomeAction methods, too.