GOTCHA 27 Object initialization sequence isn t consistent


GOTCHA #27 Object initialization sequence isn't consistent

When you create an object, the memory for the instance is allocated, each of its fields is initialized with the default value defined by the CTS, and then the constructor is invoked. If you create an object of a derived class, then all fields of the base are initialized and the constructor of the base is invoked before any field of the derived class is initialized. This is conventional wisdom derived from languages such as C++ and Java. But it is not the sequence that is followed in C#. In fact, the sequence of initialization is not the same between C# and VB.NET. Take a look at Example 3-20.

The object initialization sequence in C# is well-documented in section 10.10.3 of the C# Language Specification (see "on the web" in the Appendix"). My worry is not the fact that the object initialization sequence differs in C#, as compared to C++ or Java. It is that the sequence is not consistent between .NET languagesfor instance, between C# and VB.NET.


Example 3-20. Object initialization sequence

C# (Initialization)

 //SomeClass1.cs using System; namespace ObjectInitSequence {     public class SomeClass1     {         public SomeClass1()         {             Console.WriteLine("Constructor of SomeClass1 called");         }     } } // SomeClass2.cs using System; namespace ObjectInitSequence {     public class SomeClass2     {         public SomeClass2()         {             Console.WriteLine("Constructor of SomeClass2 called");         }     } } //Base.cs using System; namespace ObjectInitSequence {      public class Base     {         private SomeClass1 obj1 = new SomeClass1();         public Base()         {             Console.WriteLine("Constructor of Base called");         }     } } //Derived.cs using System; namespace ObjectInitSequence {      public class Derived : Base     {         private SomeClass2 obj2 = new SomeClass2();         public Derived()         {             Console.WriteLine("Constructor of Derived called");         }     } } //Test.cs using System; namespace ObjectInitSequence {     class Test     {         [STAThread]         static void Main(string[] args)         {              Derived obj = new Derived();         }     } } 

VB.NET (Initialization)

 'SomeClass1 Public Class SomeClass1     Public Sub New()         Console.WriteLine("Constructor of SomeClass1 called")     End Sub End Class 'SomeClass2.vb Public Class SomeClass2     Public Sub New()         Console.WriteLine("Constructor of SomeClass2 called")     End Sub End Class 'Base.vb  Public Class Base     Private obj1 As SomeClass1 = New SomeClass1     Public Sub New()         Console.WriteLine("Constructor of Base called")     End Sub End Class 'Derived.vb  Public Class Derived     Inherits Base     Private obj2 As SomeClass2 = New SomeClass2     Public Sub New()         Console.WriteLine("Constructor of Derived called")     End Sub End Class 'Test.vb Module Test     Sub Main()          Dim obj As Derived = New Derived     End Sub End Module 

In the above code, the class Base has a field of type SomeClass1. The class Derived, which inherits from Base, has a field of type SomeClass2. Each of these classes has a constructor that prints a message announcing itself. What is the sequence of field initialization and constructor calls when an object of Derived is created? Before you answer, you may want to ask, which language?! The C# code given above produces the output shown in Figure 3-16.

Figure 3-16. Output from C# version of Example 3-20


However, the VB.NET version of the code produces different results, shown in Figure 3-17.

Figure 3-17. Output from VB.NET version of Example 3-20


While the two programs are identical except for the language used to write them, the behavior is different. In C#, the Derived class's fields are initialized, then those of the Base class. Next, the constructors are called top-down, the Base constructor first and then the Derived constructor. In the case of the VB.NET program, however, the sequence is different (and conformant with the sequence in C++ and Java). The initialization of fields in Base and the invocation of the Base class constructor complete before any field of the Derived class is initialized.

While you are wondering about this, let me throw you some even more interesting things. What is the sequence if I derive a C# class from a VB.NET class? What happens if I derive a VB.NET class from a C# class which in turn is derived from another VB.NET class? If I derive a C# class from a VB.NET class, then the derived members will be initialized before the base members. However, if I derive a VB.NET class from a C# class, then the base members will be initialized before any derived members. In case you have more than two levels of inheritance and you mix languages between levels, the sequence depends on the language of the derived class at each level (good luck).

IN A NUTSHELL

Clearly understand the sequence in which objects are initialized in C# versus VB.NET. Understanding the sequence will help avoid surprises from this rather odd inconsistency.

SEE ALSO

Gotcha #23, "Copy Constructor hampers exensibility," Gotcha #24, "Clone() has limitations," and Gotcha #28, "Polymorphism kicks in prematurely."



    .NET Gotachas
    .NET Gotachas
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 126

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net