When constructing a C# Object, it’s important to understand the order in which the object’s fields and constructors are initialized:
- Derived static fields
- Derived static constructor
- Derived instance fields
- Base static fields
- Base static constructor
- Base instance fields
- Base instance constructor
- Derived instance constructor
Sample Program
Following is a sample C# console program that demonstrates an object’s initialization order. This program creates a “Derived” object that inherits from a “Base” object, both of which contain static and instance constructors and fields. Two fields “Field1” and “Field2” are initialized in their definitions, whereas “Field3” is initialized in the constructor. Also included is a virtual method that demonstrates why you should NOT call virtual methods from a constructor. This program writes to the console as each field and constructor is initialized so you can see the initialization order.
using System; namespace ObjectInit { class Program { static void Main( string[] args ) { Derived d = new Derived(); Console.ReadLine(); } } class Base { public Base() { Console.WriteLine( "Base.Instance.Constructor" ); this.m_Field3 = new Tracker( "Base.Instance.Field3" ); this.Virtual(); } static Base() { Console.WriteLine( "Base.Static.Constructor" ); } private Tracker m_Field1 = new Tracker( "Base.Instance.Field1" ); private Tracker m_Field2 = new Tracker( "Base.Instance.Field2" ); private Tracker m_Field3; static private Tracker s_Field1 = new Tracker( "Base.Static.Field1" ); static private Tracker s_Field2 = new Tracker( "Base.Static.Field2" ); virtual public void Virtual() { Console.WriteLine( "Base.Instance.Virtual" ); } } class Derived : Base { public Derived() { Console.WriteLine( "Derived.Instance.Constructor" ); this.m_Field3 = new Tracker( "Derived.Instance.Field3" ); } static Derived() { Console.WriteLine( "Derived.Static.Constructor" ); } private Tracker m_Field1 = new Tracker( "Derived.Instance.Field1" ); private Tracker m_Field2 = new Tracker( "Derived.Instance.Field2" ); private Tracker m_Field3; static private Tracker s_Field1 = new Tracker( "Derived.Static.Field1" ); static private Tracker s_Field2 = new Tracker( "Derived.Static.Field2" ); override public void Virtual() { Console.WriteLine( "Derived.Instance.Virtual" ); } } class Tracker { public Tracker( string text ) { Console.WriteLine( text ); } } }
Following is the console output from this sample program:
Derived.Static.Field1
Derived.Static.Field2
Derived.Static.Constructor
Derived.Instance.Field1
Derived.Instance.Field2
Base.Static.Field1
Base.Static.Field2
Base.Static.Constructor
Base.Instance.Field1
Base.Instance.Field2
Base.Instance.Constructor
Base.Instance.Field3
Derived.Instance.Virtual
Derived.Instance.Constructor
Derived.Instance.Field3
Two-Phase Construction
Note there is a potential trap with C# object initialization. While initialization starts with derived objects and moves down to the base object, the constructors initialize in reverse order, with the base constructor executing first, then the derived constructor.
The problem occurs if you attempt to call a virtual method from the base constructor. Because the derived constructor has not yet executed, the derived object may not be fully initialized when the virtual method executes from the base constructor.
As shown in the sample program, when the base constructor calls the virtual method (indicated by “Derived.Instance.Virtual” in the program output), Field3 in the derived object is not initialized because the derived constructor has not yet executed. If the virtual method depends on an initialized Field3, the program will fail.
Hence, you should not call a virtual method from an object constructor. Instead, you should perform “two-phase construction” where first you construct the object, then you call the virtual method, as follows:
Derived d = new Derived(); d.Virtual();
C# Object Initialization Tips
Some general rules and tips about C# Object initialization:
- Fields then Constructor. Fields are initialized first, then the constructor is executed.
- Static then Instance. Static fields and constructors are initialized the first time a class is accessed. Then the object’s instance fields and constructors are initialized.
- Derived then Base. For fields and static constructors, derived objects are initialized before the base object. If class C derives from B derives from A, the fields and static constructors are initialized in order C-B-A.
- Except Instance Constructors. For instance constructors, the base class constructor executes before the derived class constructor. Instance constructors are executed in order A-B-C.
- Don’t Assume Field Order. Fields are initialized in the order they are declared in the source file. However, since programmers and tools can reorder field declarations at will, you should not depend on fields being initialized in any particular order.
- Two-Phase for Virtual. Avoid calling virtual methods from a constructor. If virtual methods are required to initialize an object, use two-phase construction where you fully construct an object and then call an initialization method on the constructed object.
[…] tips, techniques and code. [Disclosure: This is my blog, of course!] (Recent Post: C# Object Initialization) […]
I just read a new article in Visual Studio Magazine by Bill Wagner, author of “Effective C#”, that discusses C# object initialization in more detail:
http://visualstudiomagazine.com/columns/article.aspx?editorialsid=2377
[…] https://www.csharp411.com/c-object-initialization/ Share this:TwitterFacebookLike this:LikeBe the first to like this. Categories: .Net, C# Comments (0) Trackbacks (0) Leave a comment Trackback […]
[…] It can make a inadequacy in an estate situation. See this couple on a vigilant initialization order:https://www.csharp411.com/c-object-initialization/ […]