Skip to main content

.NET Constructors

Introduction​

Constructors are special methods that are automatically invoked when an object of a class is created. They initialize the newly created object before it's used, ensuring that the object starts its life in a proper state. In .NET and particularly in C#, constructors play a vital role in object-oriented programming by controlling how objects are initialized.

Think of a constructor as a gatekeeper that prepares everything an object needs before allowing it to be used in your program. Unlike regular methods, constructors have the same name as the class and don't have a return type (not even void).

Basic Constructor Syntax​

Here's the basic syntax of a constructor in C#:

csharp
public class Person
{
// Fields
private string name;
private int age;

// Constructor
public Person(string personName, int personAge)
{
name = personName;
age = personAge;
}
}

To use this constructor:

csharp
// Creating a new Person object using the constructor
Person person1 = new Person("John Doe", 30);

Default Constructors​

If you don't provide any constructor in your class, C# automatically creates a parameterless default constructor that initializes all fields to their default values (null for reference types, 0 for numeric types, false for booleans, etc.).

csharp
public class Student
{
public string Name;
public int ID;

// C# automatically provides a default constructor if none is defined
// It would look like this:
// public Student() {}
}

// Usage
Student student = new Student(); // Name will be null, ID will be 0

However, once you define any constructor, C# will no longer provide the default constructor automatically.

Multiple Constructors (Constructor Overloading)​

You can define multiple constructors in a class to provide different ways to initialize objects. This is called constructor overloading:

csharp
public class Book
{
public string Title;
public string Author;
public int Year;

// Constructor with all parameters
public Book(string title, string author, int year)
{
Title = title;
Author = author;
Year = year;
}

// Constructor with two parameters
public Book(string title, string author)
{
Title = title;
Author = author;
Year = DateTime.Now.Year; // Default to current year
}

// Constructor with one parameter
public Book(string title)
{
Title = title;
Author = "Unknown";
Year = DateTime.Now.Year;
}

// Parameterless constructor
public Book()
{
Title = "Untitled";
Author = "Unknown";
Year = DateTime.Now.Year;
}
}

Example usage:

csharp
Book book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald", 1925);
Book book2 = new Book("Clean Code", "Robert C. Martin");
Book book3 = new Book("My Notebook");
Book book4 = new Book();

Console.WriteLine($"{book1.Title} by {book1.Author}, {book1.Year}");
Console.WriteLine($"{book2.Title} by {book2.Author}, {book2.Year}");
Console.WriteLine($"{book3.Title} by {book3.Author}, {book3.Year}");
Console.WriteLine($"{book4.Title} by {book4.Author}, {book4.Year}");

Output:

The Great Gatsby by F. Scott Fitzgerald, 1925
Clean Code by Robert C. Martin, 2023
My Notebook by Unknown, 2023
Untitled by Unknown, 2023

Constructor Chaining​

Constructor chaining allows one constructor to call another constructor in the same class. This helps to avoid duplicate code. In C#, you can use the this keyword to call another constructor:

csharp
public class Employee
{
public string Name;
public string Department;
public double Salary;

// Primary constructor
public Employee(string name, string department, double salary)
{
Name = name;
Department = department;
Salary = salary;
}

// Constructor that chains to the primary constructor
public Employee(string name, string department)
: this(name, department, 50000) // Default salary
{
}

// Another constructor that chains
public Employee(string name)
: this(name, "General") // Default department
{
}

// Parameterless constructor
public Employee()
: this("New Employee") // Default name
{
}
}

Static Constructors​

A static constructor is used to initialize any static data or perform a specific action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced:

csharp
public class DatabaseConnector
{
// Static field
public static string ConnectionString;

// Static constructor
static DatabaseConnector()
{
// This code runs only once when the class is first accessed
ConnectionString = "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;";
Console.WriteLine("Static constructor called. Database connection initialized.");
}

// Instance constructor
public DatabaseConnector()
{
Console.WriteLine("Instance created with connection: " + ConnectionString);
}
}

Example usage:

csharp
// Static constructor is called when the class is first accessed
Console.WriteLine("About to access the class for the first time...");
string connection = DatabaseConnector.ConnectionString;
Console.WriteLine($"Connection string: {connection}");

// Creating instances won't trigger the static constructor again
DatabaseConnector db1 = new DatabaseConnector();
DatabaseConnector db2 = new DatabaseConnector();

Output:

About to access the class for the first time...
Static constructor called. Database connection initialized.
Connection string: Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;
Instance created with connection: Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;
Instance created with connection: Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;

Private Constructors​

A private constructor is used to prevent the instantiation of a class. This is useful for classes that contain only static members:

csharp
public class MathUtilities
{
// Private constructor prevents instantiation
private MathUtilities()
{
}

// Static methods
public static double Add(double a, double b)
{
return a + b;
}

public static double Subtract(double a, double b)
{
return a - b;
}
}

Usage:

csharp
// This works because we're calling static methods
double result = MathUtilities.Add(5.2, 3.8);
Console.WriteLine($"Addition result: {result}");

// This would cause a compilation error because the constructor is private:
// MathUtilities math = new MathUtilities(); // ERROR!

Private constructors are also used in implementing singleton pattern, which ensures a class has only one instance.

Real-World Example: Product Inventory System​

Let's see how constructors can be used in a real-world scenario - a simple product inventory system:

csharp
public class Product
{
// Properties
public string ID { get; private set; }
public string Name { get; set; }
public decimal Price { get; set; }
public int StockQuantity { get; set; }
public DateTime CreatedDate { get; private set; }

// Full constructor
public Product(string id, string name, decimal price, int stockQuantity)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentException("Product ID cannot be empty");

if (price < 0)
throw new ArgumentException("Price cannot be negative");

ID = id;
Name = name;
Price = price;
StockQuantity = stockQuantity;
CreatedDate = DateTime.Now;
}

// Minimal constructor with default values
public Product(string id, string name)
: this(id, name, 0, 0)
{
}

// Method to display product info
public void DisplayInfo()
{
Console.WriteLine($"Product: {ID} - {Name}");
Console.WriteLine($"Price: ${Price}");
Console.WriteLine($"In stock: {StockQuantity} units");
Console.WriteLine($"Created on: {CreatedDate}");
Console.WriteLine();
}
}

Usage example:

csharp
// Create products using different constructors
try
{
Product laptop = new Product("P001", "Gaming Laptop", 1299.99m, 15);
Product headphones = new Product("P002", "Wireless Headphones");

// Display product information
laptop.DisplayInfo();
headphones.DisplayInfo();

// Update stock for headphones
headphones.Price = 79.99m;
headphones.StockQuantity = 50;
headphones.DisplayInfo();

// This would throw an exception
Product invalidProduct = new Product("", "Invalid Product", 10.99m, 5);
}
catch (ArgumentException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}

Output:

Product: P001 - Gaming Laptop
Price: $1299.99
In stock: 15 units
Created on: 9/28/2023 10:30:45 AM

Product: P002 - Wireless Headphones
Price: $0
In stock: 0 units
Created on: 9/28/2023 10:30:45 AM

Product: P002 - Wireless Headphones
Price: $79.99
In stock: 50 units
Created on: 9/28/2023 10:30:45 AM

Error: Product ID cannot be empty

Best Practices for Constructors​

  1. Keep constructors simple: Avoid complex logic in constructors.
  2. Initialize all relevant fields: Ensure the object starts in a valid state.
  3. Use constructor chaining: Reuse code across constructors.
  4. Validate parameters: Check for invalid values and throw appropriate exceptions.
  5. Consider providing multiple constructors: Offer different ways to initialize objects.
  6. Use default parameters (C# 4.0+) to simplify constructor overloading when appropriate.
  7. Be careful with exceptions in constructors - if an exception occurs, the object won't be created.

Summary​

Constructors are special methods in .NET that allow you to:

  • Initialize object state when it's created
  • Ensure objects start with valid values
  • Provide different ways to create objects (through overloading)
  • Set up static data for classes (using static constructors)
  • Implement design patterns like singleton (with private constructors)

Understanding constructors is crucial for effective object-oriented programming in .NET. They help you create robust classes that maintain data integrity right from the moment objects are instantiated.

Exercise Ideas​

  1. Create a BankAccount class with multiple constructors that initialize different account types (savings, checking) with appropriate default values.

  2. Implement a Logger class with a private constructor and static methods to enforce the singleton pattern.

  3. Create a ShoppingCart class with constructors that allow creating carts with pre-filled items or empty carts.

  4. Modify the Product example to include additional validation in the constructors, such as maximum price limits or valid product ID formats.

Additional Resources​



If you spot any mistakes on this website, please let me know at feedback@compilenrun.com. I’d greatly appreciate your feedback! :)