C# Constructors
Special methods inside a class called constructors are run automatically when a new instance of the class is created. They serve primarily to initialise the class members and guarantee that the newly formed object is in a consistent and functional state.
Characteristics of constructors
Important traits of constructors consist of:
- They must share the same name as the class to which they belong.
- They have no return policy, not even
void
. - As long as the constructors in a class have distinct signatures that is, different numbers, types, or orders of parameters—they can exist. We call this constructor overloading.
- When an object is created, the
new
keyword automatically invokes its constructor.
Types of Constructors
There are five constructor types supported by C#:
Default Constructor (Parameterless Constructor)
In the event that your class contains no explicit constructor definitions, the C# compiler will automatically create a public default implicit constructor. Due to its empty body and lack of parameters, this constructor mainly initialises all string/object fields to null and all numeric fields to 0. Additionally, if you would like to do some logic, like object initialisation, at the time of object creation, you can define your own user-defined default constructor (without parameters).
Example
using System;
public class Person
{
// These are instance fields (properties in this case)
public string Name { get; set; }
public int Age { get; set; }
// No constructor defined here.
// The C# compiler implicitly provides a 'public Person()' default constructor.
public void Introduce()
{
Console.WriteLine($"Hi, my name is {Name} and I am {Age} years old.");
}
}
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("--- Implicit Default Constructor Example ---");
// 1. We can create an object without passing any arguments
// because the compiler has provided the default constructor.
Person person1 = new Person();
// 2. The fields/properties are initialized to their default values:
// string (reference type) defaults to null.
// int (value type) defaults to 0.
Console.WriteLine($"person1.Name (default): '{person1.Name}'"); // Output: '' (empty string if using auto-properties implicitly, null if explicit field)
Console.WriteLine($"person1.Age (default): {person1.Age}"); // Output: 0
person1.Name = "Alice";
person1.Age = 30;
person1.Introduce();
Console.WriteLine("\n--- End of Implicit Default Constructor Example ---");
}
}
Output
--- Implicit Default Constructor Example ---
person1.Name (default): ''
person1.Age (default): 0
Hi, my name is Alice and I am 30 years old.
--- End of Implicit Default Constructor Example ---
Parameterized Constructor
This kind of constructor accepts one or more parameters, enabling you to dynamically initialise each instance of an object with various user-supplied values. A default parameterless constructor will not be provided by the compiler if you declare any parameterised constructors. You have to make a clear declaration if you still require one.
Example
using System;
namespace ConstructorExample
{
class Sample
{
public string param1;
public string param2;
// Parameterized Constructor
public Sample(string x, string y) // Accepts two string parameters
{
this.param1 = x; // Initializes param1 with the value of x
this.param2 = y; // Initializes param2 with the value of y
Console.WriteLine("Parameterized Constructor Called!");
}
public void DisplayDetails()
{
Console.WriteLine("param1: " + this.param1);
Console.WriteLine("param2: " + this.param2);
}
static void Main(string[] args)
{
// Creating an object using the parameterized constructor
Console.WriteLine("Creating obj1:");
Sample obj1 = new Sample("Welcome", "Aspdotnet-Suresh"); // Pass arguments
obj1.DisplayDetails();
Console.WriteLine("\nCreating obj2:");
Sample obj2 = new Sample("Hello", "World"); // Pass different arguments
obj2.DisplayDetails();
// Attempting to create an object without arguments will cause a compile-time error
// if no default (parameterless) constructor is explicitly defined.
// Sample obj3 = new Sample(); // This line would cause an error
}
}
}
Output
Creating obj1:
Parameterized Constructor Called!
param1: Welcome
param2: Aspdotnet-Suresh
Creating obj2:
Parameterized Constructor Called!
param1: Hello
param2: World
Copy Constructor
A copy constructor accepts as a parameter an object of the same class type. Setting the initial values of an existing object (instance) to a new object (instance) is its primary function. If necessary, you must develop your own copy constructor because C# lacks one, unlike several other languages.
Example
using System;
namespace ConstructorExamples
{
class Person
{
// Fields (properties) of the Person class
public string Name { get; set; }
public int Age { get; set; }
// Parameterized Constructor (Standard Constructor)
// Initializes a new Person object with provided name and age.
public Person(string name, int age)
{
this.Name = name;
this.Age = age;
Console.WriteLine($"Standard Constructor Called for: {this.Name}");
}
// Copy Constructor
// Initializes a new Person object by copying data from an existing Person object.
public Person(Person otherPerson) // Takes an object of the same class type as a parameter
{
// Copying the values from 'otherPerson' to the new object's fields
this.Name = otherPerson.Name;
this.Age = otherPerson.Age;
Console.WriteLine($"Copy Constructor Called for: {this.Name} (copied from {otherPerson.Name})");
}
// Method to display person details
public void DisplayDetails()
{
Console.WriteLine($"Name: {this.Name}, Age: {this.Age}");
}
static void Main(string[] args)
{
Console.WriteLine("--- Creating original object (person1) ---");
// Create the first Person object using the parameterized constructor
Person person1 = new Person("Alice", 30); // Alice is 30
person1.DisplayDetails();
Console.WriteLine("\n--- Creating a new object using Copy Constructor ---");
// Create a second Person object by copying the data from person1
Person person2 = new Person(person1); // New object initialized with person1's values
person2.DisplayDetails();
// Demonstrate that person1 and person2 are independent objects
// Changes to person1 will not affect person2, showing it's a true copy
Console.WriteLine("\n--- Modifying original object (person1) ---");
person1.Age = 31; // Change person1's age
Console.WriteLine("After modifying person1:");
person1.DisplayDetails(); // Shows Alice is now 31
person2.DisplayDetails(); // Shows the copy (person2) remains 30, demonstrating independence
}
}
}
Example
--- Creating original object (person1) ---
Standard Constructor Called for: Alice
Name: Alice, Age: 30
--- Creating a new object using Copy Constructor ---
Copy Constructor Called for: Alice (copied from Alice)
Name: Alice, Age: 30
--- Modifying original object (person1) ---
After modifying person1:
Name: Alice, Age: 31
Name: Alice, Age: 30
Static Constructor
To initialise any static data or to carry out an action that must be carried out just once for the entire class, a static constructor is declared using the static keyword. Before the first instance of the class is created or before any static members (fields, methods, or properties) are referenced for the first time, the Common Language Runtime (CLR) automatically calls it.
Key properties of static constructors
- They lack parameters and do not accept access modifiers such as private or public.
- Static constructors are limited to one per class.
- The user cannot immediately call them.
- They are only able to access the class’s static members.
Example
using System;
namespace ConstructorExamples
{
public class Bus
{
// Static field to be initialized by the static constructor
public static string Manufacturer { get; private set; }
public static int TotalBusesCreated { get; private set; }
// 1. Static Constructor
// - Called automatically before the first instance is created or any static member is accessed.
// - Does not take access modifiers (like public, private).
// - Does not take parameters.
// - There can be only one static constructor in a class.
static Bus()
{
// Initialize static fields.
Manufacturer = "Global Transit Co.";
TotalBusesCreated = 0; // Starts at 0, incremented by instance constructor
Console.WriteLine("Static Constructor Called: Initializing static data.");
Console.WriteLine($"Manufacturer set to: {Manufacturer}");
}
// 2. Instance Constructor (Parameterized Constructor)
// This is called for each new object instance.
public Bus(string model)
{
this.Model = model;
TotalBusesCreated++; // Increment static counter for each instance
Console.WriteLine($"Instance Constructor Called for: {this.Model}. Total buses: {TotalBusesCreated}");
}
// Instance property
public string Model { get; set; }
// Static method
public static void DisplayStaticInfo()
{
Console.WriteLine("\n--- Displaying Static Bus Info ---");
Console.WriteLine($"Manufacturer: {Manufacturer}");
Console.WriteLine($"Current total buses created: {TotalBusesCreated}");
}
static void Main(string[] args)
{
Console.WriteLine("Main method started.");
// Accessing a static method first. This triggers the static constructor.
Console.WriteLine("\nAttempting to call a static method (Bus.DisplayStaticInfo())...");
Bus.DisplayStaticInfo();
// Creating the first instance. Static constructor has already run.
Console.WriteLine("\nCreating first Bus instance...");
Bus bus1 = new Bus("CityCruiser X");
bus1.Model = "CityCruiser X"; // Just to be explicit, property set in constructor
Console.WriteLine($"Bus 1 Model: {bus1.Model}");
// Creating a second instance. Static constructor will NOT run again.
Console.WriteLine("\nCreating second Bus instance...");
Bus bus2 = new Bus("LongHaul Z");
Console.WriteLine($"Bus 2 Model: {bus2.Model}");
// Accessing static members again. Static constructor still won't run.
Console.WriteLine("\nAccessing static members again...");
Bus.DisplayStaticInfo();
Console.WriteLine("\nEnd of Main method.");
}
}
}
Output
Static Constructor Called: Initializing static data.
Manufacturer set to: Global Transit Co.
Main method started.
Attempting to call a static method (Bus.DisplayStaticInfo())...
--- Displaying Static Bus Info ---
Manufacturer: Global Transit Co.
Current total buses created: 0
Creating first Bus instance...
Instance Constructor Called for: CityCruiser X. Total buses: 1
Bus 1 Model: CityCruiser X
Creating second Bus instance...
Instance Constructor Called for: LongHaul Z. Total buses: 2
Bus 2 Model: LongHaul Z
Accessing static members again...
--- Displaying Static Bus Info ---
Manufacturer: Global Transit Co.
Current total buses created: 2
End of Main method.
Private Constructor
The term “private constructor” refers to a constructor with private accessibility. A class that has no public constructors and one or more private constructors stops other classes aside from nested classes from generating instances of that class outside of itself. Utility classes with only static members where no instances should be created or those that follow the Singleton design pattern frequently utilize private constructors.
Example
using System;
namespace ConstructorExamples
{
// This class is designed to be a utility class, meaning it only contains static members.
// Therefore, it should not be instantiated. A private constructor enforces this.
public class ApplicationLogger
{
// Static field to store the log file path, initialized once.
public static string LogFilePath { get; private set; }
// Static field to keep track of the total number of log entries.
public static int TotalLogEntries { get; private set; }
// Static constructor: This runs automatically once, before any static members
// are accessed or the first instance is created (though instances are disallowed here).
// It does not take access modifiers or parameters.
static ApplicationLogger()
{
LogFilePath = "application.log";
TotalLogEntries = 0;
Console.WriteLine("Static Constructor Called for ApplicationLogger: Log system initialized.");
}
// Private Instance Constructor:
// By making the constructor private, we prevent any code outside this class
// from creating new instances of ApplicationLogger.
// This is crucial for utility classes that should only expose static functionality.
private ApplicationLogger()
{
// This constructor will typically not be called if the class is used purely as a utility.
// If it were called internally (e.g., in a complex singleton where instance creation is handled by a static method),
// it would perform instance-specific initialization.
Console.WriteLine("Private Instance Constructor Called: (This should ideally not be visible if used as a pure utility).");
}
// Public static method to write log messages.
// This method can be called directly on the class without an object instance.
public static void Log(string message)
{
TotalLogEntries++; // Increment the static counter
Console.WriteLine($"[{DateTime.Now.ToShortTimeString()}] Log Entry #{TotalLogEntries}: {message}");
}
// Public static method to display current status.
public static void DisplayStatus()
{
Console.WriteLine($"Current Log File: {LogFilePath}, Entries: {TotalLogEntries}");
}
static void Main(string[] args)
{
Console.WriteLine("--- Demonstrating Private Constructor (Utility Class) ---");
// --- Attempting to create an instance will result in a compile-time error: ---
// ApplicationLogger logger = new ApplicationLogger();
// The compiler error would be:
// 'ApplicationLogger.ApplicationLogger()' is inaccessible due to its protection level.
// --- Accessing static members directly on the class ---
Console.WriteLine("\nAccessing static members of ApplicationLogger:");
ApplicationLogger.Log("Application started successfully."); // This first static member access triggers the static constructor.
ApplicationLogger.Log("User 'Admin' logged in.");
ApplicationLogger.DisplayStatus();
ApplicationLogger.Log("Data processed.");
ApplicationLogger.DisplayStatus();
Console.WriteLine("\n--- Another scenario: Singleton Pattern brief mention ---");
Console.WriteLine("Private constructors are also fundamental to the Singleton design pattern,");
Console.WriteLine("where only one instance of a class is allowed, managed by a static property or method.");
// Example of a Singleton class (simplified for illustrative purposes without full implementation here):
// public sealed class SingletonExample {
// private static readonly SingletonExample _instance = new SingletonExample();
// private SingletonExample() { /* initialization */ } // Private constructor
// public static SingletonExample Instance => _instance;
// }
}
}
}
Output
Static Constructor Called for ApplicationLogger: Log system initialized.
--- Demonstrating Private Constructor (Utility Class) ---
Accessing static members of ApplicationLogger:
[12:48 PM] Log Entry #1: Application started successfully.
[12:48 PM] Log Entry #2: User 'Admin' logged in.
Current Log File: application.log, Entries: 2
[12:48 PM] Log Entry #3: Data processed.
Current Log File: application.log, Entries: 3
--- Another scenario: Singleton Pattern brief mention ---
Private constructors are also fundamental to the Singleton design pattern,
where only one instance of a class is allowed, managed by a static property or method.
Reusing Constructors ( keyword)
This keyword allows one constructor within a class to invoke another constructor that is declared in the same class. By doing this, initialisation code repetition is reduced and consistency between constructors is guaranteed.
Example of Reusing Constructors:
using System;
public class Animal
{
public string Name { get; set; }
public int Age { get; set; }
// No parameters: calls the constructor with one parameter
public Animal() : this("Dog")
{
// Additional initialization if needed
}
// One parameter: calls the constructor with two parameters
public Animal(string name) : this(name, 1)
{
}
// Two parameters: base constructor that initializes all fields
public Animal(string name, int age)
{
Name = name;
Age = age;
}
}
class Program
{
static void Main()
{
Animal dog = new Animal(); // dog.Name will be "Dog", Age will be 1
Animal cat = new Animal("Cat"); // cat.Name will be "Cat", Age will be 1
Animal bird = new Animal("Bird", 3); // bird.Name will be "Bird", Age will be 3
Console.WriteLine($"Dog: {dog.Name}, {dog.Age}");
Console.WriteLine($"Cat: {cat.Name}, {cat.Age}");
Console.WriteLine($"Bird: {bird.Name}, {bird.Age}");
}
}
Output
Dog: Dog, 1
Cat: Cat, 1
Bird: Bird, 3
Constructors and Inheritance
When inheritance is involved, the base class’s (parent class’s) constructors are always run before the derived class’s (child class’s) constructors. This guarantees that the variables of the base class are correctly initialised before they are used or extended by the derived class.
- When a derived class constructor fails to call a base class constructor directly, the default (parameterless) constructor of the base class is called implicitly.
- If the base class only has parameterised constructors and no default constructor, the derived class must use the : base() keyword to explicitly invoke one of the base class’s parameterised constructors. This call is positioned in between the body and signature of the derived constructor. Base() may receive parameters from other expressions or from the parameters of the derived class.
Example of Constructors with Inheritance:
using System;
public class Animal
{
protected string name;
public Animal() // Base class default constructor
{
Console.WriteLine("In Animal's default constructor");
}
public Animal(string name) // Base class parameterized constructor
{
this.name = name;
Console.WriteLine("In Animal's constructor with 1 parameter: {0}", this.name);
}
}
public class Dog : Animal // Dog inherits from Animal
{
public Dog() : base() // Explicitly calls base class's default constructor
{
Console.WriteLine("In Dog's default constructor");
}
public Dog(string name) : base(name) // Explicitly calls base class's parameterized constructor
{
Console.WriteLine("In Dog's constructor with 1 parameter: {0}", this.name);
}
}
class Program
{
static void Main()
{
Console.WriteLine("Creating Dog with default constructor:");
Dog dog1 = new Dog();
// Output:
// In Animal's default constructor
// In Dog's default constructor [98]
Console.WriteLine("\nCreating Dog with parameterized constructor:");
Dog dog2 = new Dog("Rex");
// Output:
// In Animal's constructor with 1 parameter: Rex
// In Dog's constructor with 1 parameter: Rex
}
}
Output
Creating Dog with default constructor:
In Animal's default constructor
In Dog's default constructor
Creating Dog with parameterized constructor:
In Animal's constructor with 1 parameter: Rex
In Dog's constructor with 1 parameter: Rex
Field Initialization Order
The sequence in which an object’s non-static fields are initialised when its constructor is called is as follows:
Memory allocation: All of the non-static fields have memory allotted to them.
Default value initialization: Fields are set to their default values, which include null for reference types, false for bool types, and 0 for numeric types.
Inline field initializers: If a field has an inline initialiser, then that value is assigned next (private string name = “Rex”;, for example).
Constructor body execution: The code inside the constructor’s body is finally run, enabling more intricate initialisation logic or additional assignment. This implies that values set in the constructor body will take precedence over those set by inline initialisers.
You can also read What Is Mean By Classes In C# With Code Examples?