C# Constructor Gotchas Part 1: Calling virtual methods from a constructor

What could go wrong if we call an overridable method from within a constructor?

If you’ve used static code analysis tools then you may have come across a warning instructing you not to call virtual methods in constructors.
This particular warning is one that should not be ignored, and nor should it be suppressed without good reason. It is of particular relevance to those moving to C# from some other object oriented languages which do not behave in quite the same way (more on that later).

This is part of a series of posts featuring simple but informative code samples.
You can find a bit of background information and a list of the other posts in the series here.

Consider a simple example:

If you haven’t seen this before, please scroll back up and take a moment to read through the code and decide what you think the output will be, before reading on.

When I gave this and similar other examples to people as part of a test, what surprised me was not that people got it wrong, but the variety of different incorrect answers.

This example is rather contrived, but hopefully illustrates the kind of potential problems that could arise, especially if you were writing the derived class without visibility of the base class source code.

If we compile this code and run the static code analysis in Visual Studio, we receive the warning CA2214: Do not call overridable methods in constructors

The message detail (and the build output window) contains the following:

Now, did you read through the source code and work out what you think the output would be?

If your answer included Base class has nothing to say, then I’m afraid you’re wrong, and this might be a good opportunity to brush up on virtual members and what happens when they are called.

The next most common incorrect answer is probably: Derived class says Number = 42

However, the actual output from this program is: Derived class says Number = 0

When we create the new instance of DerivedClass, the default parameterless constructor in BaseClass is called first. This in turn calls the virtual function SaySomething().
When BaseClass calls this.SaySomething(), the call to the virtual method is directed to the overriden SaySomething() in DerivedClass.
This in turn prints the value of Number to the console output.
However, at this point the code in DerivedClass’s constructor has not yet executed, and so the value of number is equal to default(int), i.e. zero.
The value of Number in DerivedClass then gets set to the value we passed in to the constructor, but too late to affect the output.

If you are working on a new project from the outset and have no exceptional reason to violate this code analysis rule (or on an existing project with no current CA2214 warnings), then I would suggest adding CA2214 to the list of warnings that you ask Visual Studio to treat as errors.
Personally, when I have the luxury of beginning a project from scratch, I set Visual Studio to treat all warnings as errors on Release builds and if I encounter a warning for something which there is a justifiable reason and which cannot be written another way, then I add in-code suppression attributes with detailed justification notes.

Returning to the code example given at the beginning, we can build in Debug mode and use reflection together with a few more console output lines in order to see the execution path of the code from the program output. (You could also step through line by line in the debugger, but this gives something to show here.)
I have also added two additional calls to the SaySomething method, one in the constructor for Derived class, and one to the BaseClass implementation from SaySomething in DerivedClass. This allows us to see more clearly the before and after effect.

When we run the above code, the output to the console is:

Earlier I mentioned that not all object oriented languages behave the same way. If you find yourself having to switch from one to another, then this code sample provides a good way of demonstrating the differences in object initialization strategies in each language.

In C#, when we create an instance of a derived class, the object is always considered to be an instance of the derived class (as illustrated in the output panel above by the value of this.GetType().Name that is output from the base class constuctor).
Even when the code is executing the base class constructor and has not yet arrived at the derived class constructor, if the base class uses the object reference this, the type of that object is that of the derived class, and a call to a virtual method which is overriden in the derived class will execute the override rather than the base class method.

C++ behaves differently.
When the new object is being instantiated and the base class constructor is being executed (i.e. prior to execution of the derived class constructor), if we use the pointer this (or implicitly do so by accessing an instance method or field), then the type of object returned at that time appears and behaves as an instance of the base class.
Only once we have begun to execute the derived class constructor does the this pointer begin to reference an instance of the derived class. It is as if the class begins its life as one type and then morphs into the more specialised type as the initialization runs down the chain of inheritance.

We can observe this, and the effect on virtual methods called from a constructor, by converting the previous C# code to C++.
(Note that for the sake of brevity, preprocessor directives have been omitted. My test environment for this was a Win32 console application with “stdafx.h” and “typeinfo.h” included.)

When we run this and look at the output with runtime type information, then the difference in behaviour is clear:

While the derived class appears to behave in exactly the same way as it does in C#, the base class under initialization does not.

Comparing the two, we see that in C# the value of this.GetType().Name is “DerivedClass” when called from the BaseClass constructor during initialization of a DerivedClass instance.
By contrast in C++, typeid(*this).name() in the BaseClass implementation of SaySomething() returns “class BaseClass” at first when called from the BaseClass constructor, but later returns “class DerivedClass” once the DerivedClass constructor has begun to execute.
The output also clearly illustrates that (unlike C#) the vall to the virtual method during BaseClass constructor results in a direct call to BaseClass::SaySomething() – which makes sense because the object has effectively not yet become an instance of DerivedClass.

Thanks for reading. Hopefully you found something of interest.

If you have something to add, a mistake to point out, or would just like to let me know what you thought, then please feel free to add a comment using the box below or to contact me on Twitter or Google+.

2 thoughts on “C# Constructor Gotchas Part 1: Calling virtual methods from a constructor”

  1. Great article. C++ actually has a special convention for handling just these situations with ultimate control. They are called Initialization lists and it is a list of base class constructors (and the arguments you want to pass to them) placed just after the method definition. Here is a better explanation: http://www.cprogramming.com/tutorial/initialization-lists-c++.html
    C# and VB both have TERRIBLE OOP patterns IMHO and this is a prime example of why. Until something like this is implemented they can’t support multiple inheritance even if they wanted to, BTW.

Leave a Reply to Kevin Rowe Cancel reply