C# Class Constructor Overloading


This entry is part 3 of 8 in the series C# Classes Intermediate

What is constructor overloading? We can create custom constructors. We will use an example of two custom constructors in our example code. When we do this, the compiler will no longer create a parameterless constructor for us. This means that when we instantiate our class into an object, we can no longer supply zero parameters. We need to go back to the class and create our own paramterless constructor.

Before getting deep into this, we need to be aware that creating a whole bunch of constructors that aren’t absolutely necessary is considered bad practice. However there are times when it may be necessary. Also, if you are maintaining code with several construcntors you will need to know how they work.

In the code below we have the default constructor plus two overloads. When you put your cursor in the brackets you get the message as seen in the screen shot.

Here is the first example code. We are not done yet however.

namespace Constructors1
{
    public class Customer
    {
        public string Name;  // in real world these are private
        public int Id;  // in real world these are private
        public Customer()
        {
        }
        public Customer(int id)
        {
            this.Id = id;  // set Id property
        }
        public Customer(int id, string name)
        {
            this.Id = id;  // this references the current object
            this.Name = name;  // here we set Name property
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //var customer = new Customer();
            // above gives ERROR not contain a constructor that takes zero arguments
            // unless we create OUR OWN parameterless constructor
            var customer = new Customer();
              
            Console.WriteLine(customer.Name);
            Console.ReadKey();
        }
    }
}

Let’s change the code a bit, as shown below and this works. On the console we get our two parameters.

            var customer = new Customer(4, "Jack");
            Console.WriteLine(customer.Id);  
            Console.WriteLine(customer.Name);

When to use Constructors

We only use constructors when we really need to initialize an object. Our code can get very cluttered if we have 10 fields and we need to create different combinations of constructors. What we can do is set the properties using the following style of code instead of using constructors.

            var customer = new Customer();
            customer.Id = 7;
            customer.Name = "John";

There are however times when you may need to initialize and object to an early state and you might want to use constructors for this purpose.

One-to-Many

Suppose you also have an Order class. You want to create a list of Orders. Customers can have zero, one or many orders. You need to set this up to handle this. Whenever you have a class, such as our Customer, and inside that class you have a List of objects of any type, you should always initialize that list to an empty list. Here is why.

If you create a variable that is a reference type, an it is not initialized, the value will be null. Our objects are reference types. Therefore, if we create an instance of our class and the class is not initialized, we might get an exception of type Null Reference Exception.

The List is a Generic class that takes a parameter between the angled brackets, like this: List.

namespace Constructors2
{
    public class Customer
    {
        public string Name;  // in real world these are private
        public int Id;  // in real world these are private
        public List<Order> Orders;
        public Customer()
        {
            Orders = new List<Order>();  // important!
        }
        public Customer(int id) : this
        {
            this.Id = id;  // set Id property
        }
        public Customer(int id, string name) : this
        {
            this.Id = id;  // this references the current object
            this.Name = name;  // here we set Name property
        }

    }
    public class Order { }  // just tmake it empty for now
    
    class Program
    {
        static void Main(string[] args)
        {
            var customer = new Customer();
            customer.Id = 7;
            customer.Name = "John";

            var order = new Order();
            // DO NOT Do THIS: Customer.Orders = new List<Order>();
            // it is the responsibility of Customer to initialize Orders!
            customer.Orders.Add(order);

            Console.WriteLine(customer.Id);
            Console.WriteLine(customer.Name);
            Console.ReadKey();
        }
    }
}

: this

It’s good that we have initialized our list of orders in the customer class. However, we have a problem. What if the caller of our code supplies an integer upon instantiation. Right now, the constructor will not initialize the list of orders to an empty list (which is not the same as null). We could initialize the list of order in each constructor, but there is an easier way to code this. Use colon this. In the code below, the default constructor is called first. After that code executes, the Id property is set.

        public Customer(int id) : this()
        {
            this.Id = id;  // set Id property
        }

Have a look at the following line of code. We are passing control to the constructor with id. We are saying: “do this first”. Once the constructor with the id gets control, it redirects control to the default constructor. Therefore, the first thing that happens when the caller instantiates our Customer, is the list of Orders is initialized to an empty list(not null). If it was not initialized, we will get an NullReferenceException.

public Customer(int id, string name) : this(id)

Complicated and Redundant

Actually, other than our default constructor, the other two constructors are not necessary in this case. We should probably just delete them. Currently our code is a bit hard to maintain. We can use many constructors, but best practices says only use them when you need to use them, as in our default constructor initializing a list of objects.

Indexers

Jumping ahead a bit we will attempt to show how indexers work with our Orders. Look at the code below. We have a problem. This code runs but we get 7, John, 9, 9 as output. Why?

    public class Order 
    {
        public int Id;  // add a property
    }  
    
    class Program
    {
        static void Main(string[] args)
        {
            var customer = new Customer();
            customer.Id = 7;
            customer.Name = "John";
            var order = new Order();

            customer.Orders.Add(order);
            customer.Orders.Add(order);
            customer.Orders[0].Id = 8;
            customer.Orders[1].Id = 9;
            Console.WriteLine(customer.Id);
            Console.WriteLine(customer.Name);
            Console.WriteLine(customer.Orders[0].Id);  // 9 ???
            Console.WriteLine(customer.Orders[1].Id);  // 9
            Console.ReadKey();
        }
    }
Series Navigation<< C# Class ConstructorsC# Static Fields >>