C# Default Constructor: How It Works and When to Use It
c# default constructor: Understand how C# default constructors work, when the compiler generates them, and how to control object initialization in classes and structs.
c# default constructor requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.
In C#, a default constructor is a parameterless constructor that the compiler provides automatically when you do not declare any constructors for a class. It initializes all instance fields to their default values: numeric types to zero, bool to false, and reference types to null. This behavior is convenient, but it has important implications for object initialization, inheritance, and maintainability.
What the Compiler Generates for a Class
When you define a class without any constructor, the C# compiler adds a public parameterless constructor. For example:
public class Order { public int Id { get; set; } public string CustomerName { get; set; } }
The compiler generates a constructor equivalent to:
public Order() { base(); }
This constructor calls the base class's parameterless constructor (which is object if no base is specified) and then sets fields to their default values. The generated constructor is public, so you can instantiate the class with new Order().
When the Compiler Does Not Generate One
If you define any constructor, even one with parameters, the compiler stops generating the default constructor. This is a common source of confusion. For example:
public class Invoice { public Invoice(decimal amount) { Amount = amount; } public decimal Amount { get; set; } }
Now new Invoice() fails to compile because no parameterless constructor exists. If you still need one, you must add it explicitly:
public Invoice() { }
This rule exists because the presence of a custom constructor signals that the class requires specific initialization. The compiler cannot assume that a parameterless version is safe.
Default Constructors in Structs
Structs behave differently. In versions of C# before 10, every struct has an implicit public parameterless constructor that you cannot override. It initializes all fields to their default values. For example:
public struct Point { public int X; public int Y; }
You can always call new Point() and get X and Y set to 0. In C# 10 and later, you can define an explicit parameterless constructor for a struct, but it must assign a value to every field. This is a deliberate change that gives structs more flexibility while preserving value-type semantics.
Field Initialization and Default Values
The default constructor runs field initializers before the constructor body. Field initializers are expressions assigned at declaration:
public class Settings { public int Timeout = 30; public string Name = "default"; }
When the default constructor is used, Timeout becomes 30 and Name becomes "default". Without field initializers, the fields get the type's default value: 0 for int, null for string, and so on. This distinction matters when you later add a parameterized constructor: field initializers still run, but the constructor body can override them.
Overriding the Default Constructor
You can replace the implicit default constructor by declaring an explicit parameterless constructor. This is useful when you need to set up a known state or validate invariants:
public class Repository { private readonly string _connectionString; public Repository() { _connectionString = "localhost:5432"; } }
Once you do this, the compiler no longer generates any other constructor. If you also want a constructor that accepts a connection string, you must add it separately and decide whether it chains to the parameterless one.
Inheritance and Constructor Chaining
When a derived class uses its default constructor, it implicitly calls the base class's parameterless constructor. If the base class does not have a parameterless constructor, the derived class must explicitly call a base constructor using base(...). For example:
public class Base { public Base(string name) { } } public class Derived : Base { public Derived() : base("default") { } }
If you rely on the implicit default constructor in a derived class, the base class must have a parameterless constructor. Otherwise, compilation fails. This is a common design constraint when adding constructors to base classes.
Practical Implications for Serialization and Dependency Injection
Many frameworks, such as ASP.NET Core's dependency injection container and JSON serializers like System.Text.Json, require a public parameterless constructor to instantiate types automatically. If you define only a parameterized constructor, those tools may fail unless you configure them to use a custom constructor. This is a practical reason to keep a parameterless constructor, even if it is not the primary way you create instances. However, a parameterless constructor that leaves fields in an invalid state can cause bugs. Consider whether you need to initialize fields to safe defaults or use nullable reference types to signal uninitialized state.
Common Mistakes and How to Avoid Them
A frequent mistake is adding a parameterized constructor and forgetting that the default constructor disappears. This breaks code that relied on new MyClass(), including serialization and reflection-based instantiation. Another mistake is assuming that a struct's explicit parameterless constructor is available in older C# versions. Always verify the language version you are targeting. When you do define a parameterless constructor, ensure it does not leave the object in a partially initialized state that violates invariants. If the class is meant to be immutable, consider making the constructor the only way to set fields.