Author avatar

Dániel Szabó

Call Chain of Constructors in C#

Dániel Szabó

  • Jan 2, 2020
  • 8 Min read
  • 223 Views
  • Jan 2, 2020
  • 8 Min read
  • 223 Views
Languages Frameworks and Tools
C#

Introduction

The idea to share initialization code across your different constructors was born long ago. This is often referred to as constructor chaining in the C# world. This guide will teach you how to utilize this technique, show you how to use it to your own advantage, and give you some tricks that allow you to expand on the idea and find your own solutions.

You could say this is the art of calling constructors from other constructors in the same class or from the base class.

Constructors

Whenever a class or struct is created or instantiated, the constructor of the corresponding class is called. The classes can have multiple constructors with different arguments to allow you to flexibly craft them to your own needs.

Let's take an example of a constructor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;

namespace cnstructors
{
    public class ConstructMe
    {
        public string name;
        public int id;
        public ConstructMe(string Name, int id)
        {
            this.name = Name;
            this.id = id;
        }

    }
    class cnstrct
    {
        static void Main(string[] args)
        {
            ConstructMe a = new ConstructMe("Daniel", 28);
            Console.WriteLine($"The instance with name: {nameof(a)}, has property name: {a.name} and id: {a.id}");
            Console.ReadKey(); ;
        }
    }
}
csharp

Calling the code gives us the following output.

1
The instance with name: a, has property name: Daniel and id: 28
bash

This code section is called the constructor.

1
2
3
4
5
public ConstructMe(string Name, int id)
    {
        this.name = Name;
        this.id = id;
    }
csharp

It allows the instance customization, and also lets you incorporate flexibility into your application based on different requirements.

You have the option not to create constructors for your classes; however, you need to know that behind the scenes they will be generated based on your member variables will be set to their default values.

We differentiate four types of constructors:

  1. Instance
  2. Private
  3. Static
  4. Copy

Static constructors initialize only static members of the type.

Private constructors are special constructors used only in classes that contain only static members.

Copy constructors take as an argument an instance of the same class.

Instance constructors are the most commonly used. They initialize the instance member variables when you use the new expression.

Chaining Constructors and Constructor Overloading

Constructor chaining is strongly coupled with constructor overloading. Overloading means creating different versions for our constructor to accommodate the needs of different situations. For example, an application could have an employee class that allows us to create new employees in our systems. We could have different constructors based on the amount of information we have in advance from new employees.

This class would allow us to flexibly implement different initialization for a new employee. We have the option to instantiate without any arguments, and we can do it with one or two arguments at the same time.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class NewEmployee {
        public string firstName;
        public string lastName;
        public NewEmployee(){
            Console.WriteLine("Reserving new record for the upcoming employee.");
        }
        public NewEmployee(string firstName) {
            this.firstName = firstName;
            Console.WriteLine("Creating new record for the upcoming employee, with firstName!");
        }
        public NewEmployee(string firstName, string lastName) {
            this.lastName = lastName;
            this.firstName = firstName;
            Console.WriteLine("Creating new record for the upcoming employee, with firstName and lastName!");
        }
    }
csharp

This example suffers, however, from a fatal flaw. We usually prefer to initialize every record-related attribute with a single call for our employee instead of trying to find or craft the appropriate arguments based constructors for our situation. How could we improve on these constructors with very little coding? We would love to have a default firstName and lastName assigned.

Enter constructor chaining.

The syntax for this is as follows.

1
2
3
4
5
6
7
public NewEmployee():this("Default firstName","Default lastName"){
    Console.WriteLine("Reserving new record for the upcoming employee.");
}
public NewEmployee(string firstName):this(firstName,"Default lastName") {
    this.firstName = firstName;
    Console.WriteLine("Creating new record for the upcoming employee, with firstName!");
}
csharp

The key is the :this() keyword, which is a reference to another constructor. The order of the call is as follows: First, we call the constructor which is referenced with the :this() keyword, and if that also references another constructor, it will also call that constructor, climbing up the call chain.

Let's build a fully fledged example to climb the chain.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
using System;

namespace cnstructors
{

    public class NewEmployee {
        public string firstName;
        public string lastName;
        public string empID;
        public string position;
        public string team;
        public NewEmployee():this("Default firstName","Default lastName"){
            Console.WriteLine("Reserving new record for the upcoming employee.");
        }
        public NewEmployee(string firstName):this(firstName,"Default lastName") {
            this.firstName = firstName;
            Console.WriteLine("Creating new record for the upcoming employee, with firstName!");
        }
        public NewEmployee(string firstName, string lastName) :this(firstName, lastName, "XC007","Java Developer","The JAVA team"){
            this.lastName = lastName;
            this.firstName = firstName;
            Console.WriteLine("Creating new record for the upcoming employee, with firstName and lastName!");
        }
        public NewEmployee(string firstName, string lastName, string empID, string position, string team) {
            this.firstName = firstName;
            this.lastName = lastName;
            this.empID = empID;
            this.position = position;
            this.team = team;
            Console.WriteLine("Creating new record for the upcoming employee, with firstName, lastName, empID, position and team!");
        }
    }

    class cnstrct
    {
        static void Main(string[] args)
        {
            Console.WriteLine("First construct!");
            NewEmployee a = new NewEmployee();
            Console.WriteLine("Second construct!");
            NewEmployee b = new NewEmployee("Daniel");
            Console.WriteLine("Third construct!");
            NewEmployee c = new NewEmployee("Daniel", "Szabo");
            Console.ReadKey(); ;
        }
    }
}
csharp

The output of our execution perfectly demonstrates how the chain works.

1
2
3
4
5
6
7
8
9
10
11
First construct!
Creating new record for the upcoming employee, with firstName, lastName, empID, position and team!
Creating new record for the upcoming employee, with firstName and lastName!
Reserving new record for the upcoming employee.
Second construct!
Creating new record for the upcoming employee, with firstName, lastName, empID, position and team!
Creating new record for the upcoming employee, with firstName and lastName!
Creating new record for the upcoming employee, with firstName!
Third construct!
Creating new record for the upcoming employee, with firstName, lastName, empID, position and team!
Creating new record for the upcoming employee, with firstName and lastName!
bash

Basically, the last constructor called is first in the chain of calls.

Conclusion

We started by defining how constructors work and what they are. Then we drew up a theoretical example and first implemented it with constructors without chaining, then improved upon it by adding constructor chaining by calling additional constructors to initialize our instances. I hope this was worth your time and you found what you were looking for. Thanks for reading.

0