Inherited C# and VB.Net Objects Initialize Fields in a Different Sequence
If you’ve ever run FxCop and seen rule #CA2214 “Do not call overridable methods in constructors”, here’s a good example of why you should avoid this mistake. Consider the following contrived example code in C#:
Firstly the base class that contains the virtual call in the constructor:
1: abstract class BaseClass
2: {3: public BaseClass()
4: { 5: SomeInitialization(); 6: } 7: 8: public abstract void SomeInitialization();
9: }Then the class that inherits from BaseClass overrides the SomeInitialization function and accesses a field in the subclass:
1: class DerivedClass : BaseClass
2: {3: object foo = new object();
4: 5: public override void SomeInitialization()
6: {7: foo.ToString();//foo has been initialized
8: } 9: }Creating a new instance of DerivedClass succeeds because
- Field “foo” is initialized with “new object()”
- The constructor of BaseClass is called which in turn calls
- The virtual “SomeInitialization” in DerivedClass.
However in VB.Net what appears to be the same code, will in fact fail:
The base class:
1: MustInherit Class BaseClass
2: Public Sub New()
3: SomeInitialization()4: End Sub
5: 6: Public MustOverride Sub SomeInitialization()
7: End Class
The derived class:
1: Class DerivedClass
2: Inherits BaseClass
3: 4: Private foo As New Object()
5: 6: Public Overrides Sub SomeInitialization()
7: foo.ToString() 'This line will fail because x has not been initialized.
8: End Sub
9: End Class
In the Visual Basic code, the sequence is
- The constructor of BaseClass is called which in turn calls
- The virtual “SomeInitialization” in DerivedClass.
- Field “foo” is initialized with “new object()”
But it will never reach step 3 because step 2 fails with a NullReferenceException. Also be careful of naive fixes like the following:
1: Class NaiveFix
2: Inherits BaseClass
3: 4: Private x As New List(Of String)
5: 6: Public Overrides Sub SomeInitialization()
7: x = New List(Of String)
8: x.Add("A Value")
9: End Sub
10: End Class
In this case field “x” is initialized inside the “SomeInitialization” function, an item added to the list, and is then re-initialized once the constructor sequence has completed, resulting in an empty list. This is one of those sneaky language differences to catch the unwary.