0

I know that the following is the order of data members initialization and constructor call when creating a derived class object.

  1. Derived static fields
  2. Derived static constructor
  3. Derived instance fields
  4. Base static fields
  5. Base static constructor
  6. Base instance fields
  7. Base instance constructor
  8. Derived instance constructor

Everything here seems pretty logical except for ONE thing:
I can not understand why is that that derived class fields get initialized before base class fields? Honestly I can not find any valid and logical explanation for that after scouring the internet and giving it a lot of thought.

Erik_JI
  • 287
  • 1
  • 7
  • Perhaps the need exists to pass in the derived instance fields to a base constructor. – Ibrennan208 Jul 22 '22 at 20:52
  • 1
    note: for static fields, it may additionally depend on whether `beforefieldinit` gets set, which is nuanced and hard to describe – Marc Gravell Jul 22 '22 at 20:53
  • @MarcGravell If we focus on _"derived class fields get initialized before base class fields"_ - do you happen to know of any official reasoning or technical reason for that? Or is it just one of those "We could have done A or B. Jeff liked A, so we did that." – Fildor Jul 22 '22 at 20:56
  • 1
    Does this answer your question? [C# constructor execution order](https://stackoverflow.com/questions/1882692/c-sharp-constructor-execution-order) – Progman Jul 22 '22 at 21:21
  • Unfortunately, that question referes to the order of constructor calls _not_ to the order of field initializations, so, no, It does not answer my question. – Erik_JI Jul 23 '22 at 11:47

2 Answers2

2

Consider the following class structures:

Animal:

public class Animal
{
    public string Name;
    public Animal(string name)
    {
        Name = name;
    }
}

Dog (which is derived from Animal):

public class Dog : Animal
{
    static string DogName = "Dog";

    public Dog() : base(DogName)
    {
                
    }
}

And Cat (which is also derived from Animal):

public class Cat : Animal
{
    public Cat() : base(nameof(Cat))
    {

    }
}       

If we wanted to instantiate a copy of Dog or Cat, they will both ultimately call the Animal constructor. The Animal constructor requires a string, name, be passed in as a parameter. In order for the name parameter to be passed in from either the Cat or Dog it will need to be defined somewhere. So it would have to be defined before calling the Animal constructor, but the compiler wouldn't know to do this until already trying to initialize the derived class. So ultimately, it would need to initialize at least some of the values in the derived class in order to use them to call the constructor of the base class.

For Dog, it will initialize the static DogName in order to pass it into the constructor of the base class, while for Cat, the compiler will evaluate the nameof(Cat) to pass in to the Animal constructor.


To try to capture why it would make sense to initialize some of these values, let's imagine we are the compiler trying to create a new Dog (take this all as pseudocode -- words meant to describe logic, rather than fit the syntax of the current language -- the following is not C#):

var dog = new Dog():

  1. Initialize all the variables in Dog that we already know the value of (in case we need them during construction):

    static string DogName = "Dog";

  2. Check the constructor and see that we actually need to construct the Dog base class, Animal:

    var animal = new Animal(string name) <- This is where we pass in the DogName

  3. Initialize all the variables in Animal that we already know the value of (in case we need them during construction):

    public string Name;

*(We would then repeat steps 2 and 3 until we hit the base Object class, which we then construct to begin the foundation of our Animal in this case)

  1. Construct our Animal, using the name passed in, which was DogName (from step 2)

    Name = name;

  2. Construct our Dog from that Animal:

    Dog = fresh instance of Animal (We didn't have anything else to do in the Dog constructor)


If we skipped step 1 it would be a bit annoying to have to go all the way back to whichever class actually creates the original value for name.

In a more complex example, if we didn't have it yet, we would need to go back to the previous class to see what was passed in as the parameter in the constructor. If that class didn't have it, we would have to repeat this for every class all the way back to the original one that initializes the referenced value, and then go all the way back to the current constructor we were looking at.

Although that would work, in a sense it also retraces our steps. It is a bit more convenient to step through all the classes we would need and ensure we have all the values we may need along the way, and then once we get to the end of our path, we can return back along it a single time.


Just something fun to add as something to watch out for, which is when you have a member variable that when initialized, initializes forever. If that happens you get a Stack Overflow error because the list of managed values becomes unmanageable, since you're trying to hold all of the initialized values while continuing to the base class.

An example of that would be if you try to create an instance of the following C# class:

public class StackOverflow
{
    public StackOverflow stackOverflow = new StackOverflow();

    public StackOverflow(){ }
}
Ibrennan208
  • 1,345
  • 3
  • 14
  • 31
  • thank you for your answer, but your explanation does not relly tell why would the compiler need to initialize derived class fields before the base class fields. You say that Ity would need to do so, so that It can call the bae class constructor. But the base class constructor is called _after_ both base class and derived class fields are initialized. If I am getting soemething wrong, please correct me. – Erik_JI Jul 23 '22 at 11:46
  • Base class can accept values from derived class in the constructor, not the other way around. So base class will need to initialize at least some of the derived class in order for its constructor to be used if the derived class is passing in its own values through the base constructor. If it happened in the other order, when base constructor gets called, it would be possible to be missing value references, since the value for the constructor parameters have yet to be initialized. – Ibrennan208 Jul 23 '22 at 17:12
  • So what I'm saying is, it initializes the base values and derived fields, and then calls the base constructor, with the idea that values from the derived class could potentially be passed through the constructor. You would have to have the values initialized before passing them into the constructor (like any other method call, you would need to define the parameter values before supplying them to the parameter). – Ibrennan208 Jul 23 '22 at 17:15
  • Thank you very much. I would be so gratefull if you could show It on an example so I avoid confusion. – Erik_JI Jul 23 '22 at 19:45
  • @Erik_JI I've added more to hopefully clarify. – Ibrennan208 Jul 23 '22 at 21:15
1

Logically, you might want to use the initialized value in the constructor.

See:

public class Base
{
    private int x = 3;

    public Base()
    {
        Print();
    }

    protected virtual void Print()
    {
        Console.WriteLine(x);
    }
}

public class Derived : Base
{
    private int x = 5;

    protected override void Print()
    {
        base.Print();
        Console.WriteLine(x);
    }
}

Note: this is exactly why you shouldn't call virtual methods from the constructor because your object might not be fully initialized.

Wouter
  • 2,540
  • 19
  • 31