Question
You have a C# class with two constructors that both initialize readonly fields.
One constructor receives the final value directly, while the other performs some conversion first and then assigns the result. You want to avoid duplicating the field assignment logic.
For example:
public class Sample
{
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
_intField = i;
}
public Sample(int theInt) => _intField = theInt;
public int IntProperty => _intField;
private readonly int _intField;
}
The problem is:
- You do not want to duplicate the assignment code.
- The field is
readonly, so it must be assigned during construction. - Moving the shared logic to a normal helper method does not solve the
readonlyinitialization requirement. - You want to know how to call one constructor from another in C#.
How can this be done cleanly and correctly?
Short Answer
By the end of this page, you will understand constructor chaining in C#, how to use this(...) to call one constructor from another, and why this is especially useful when initializing readonly fields without duplicating code.
Concept
In C#, a class can have multiple constructors. This is called constructor overloading. Often, several constructors perform similar setup work, which can lead to duplicated code.
To avoid that duplication, C# supports constructor chaining. This means one constructor can call another constructor in the same class by using this(...).
For your example, one constructor already knows how to fully initialize the object:
public Sample(int theInt) => _intField = theInt;
The string-based constructor does not need to assign the field itself. It can first convert the string to an int, then pass that value to the other constructor:
public Sample(string theIntAsString) : this(int.Parse(theIntAsString))
{
}
This matters because:
- It keeps initialization logic in one place.
- It works correctly with
readonlyfields. - It makes classes easier to maintain.
- It reduces bugs caused by forgetting to update all constructors.
A readonly field can be assigned:
- where it is declared, or
- inside a constructor
Constructor chaining still counts as constructor-time initialization, so it is the standard solution here.
Mental Model
Think of constructors like different entrances to the same building.
- One entrance accepts an
intdirectly. - Another entrance accepts a
string, but first converts it into anint.
Instead of building two separate check-in desks, you create one main check-in desk. The string entrance simply forwards visitors to the int entrance after converting the value.
So:
Sample(int)= the main entrance that performs the real setupSample(string)= a convenience entrance that prepares the value and forwards it
This way, all important setup happens in one place.
Syntax and Examples
Core Syntax
To call another constructor in the same class, use : this(...) after the constructor signature.
public ClassName(argumentType value) : this(otherValue)
{
}
Your Example Using Constructor Chaining
public class Sample
{
private readonly int _intField;
public Sample(int theInt)
{
_intField = theInt;
}
public Sample(string theIntAsString) : this(int.Parse(theIntAsString))
{
}
public int IntProperty => _intField;
}
What this does
Sample(int)performs the actual field assignment.Sample(string)parses the string and forwards the result._intFieldis assigned only once.
Another Example
public class User
{
private readonly string _name;
private readonly int _age;
public User(string name, int age)
{
_name = name;
_age = age;
}
public User(string name) : this(name, 18)
{
}
public string Name => _name;
public int Age => _age;
}
Explanation
Here, the one-argument constructor supplies a default age and delegates to the main constructor.
Using Expression-Bodied Constructors
Your original code used one. You can still combine styles if you want:
public class Sample
{
private readonly int _intField;
public Sample(int theInt) => _intField = theInt;
public Sample(string theIntAsString) : this(int.Parse(theIntAsString))
{
}
public int IntProperty => _intField;
}
That is valid C# and keeps the code concise.
Step by Step Execution
Consider this code:
var sample = new Sample("42");
Console.WriteLine(sample.IntProperty);
With this class:
public class Sample
{
private readonly int _intField;
public Sample(int theInt)
{
_intField = theInt;
}
public Sample(string theIntAsString) : this(int.Parse(theIntAsString))
{
}
public int IntProperty => _intField;
}
Step by step
new Sample("42")is called.- C# selects the constructor that accepts a
string. - Before that constructor body runs, the
: this(int.Parse(theIntAsString))part executes. int.Parse("42")returns42.- C# calls
Sample(int)with42. - Inside
Sample(int),_intFieldis assigned42. - Control returns to the
Sample(string)constructor body. - Its body is empty, so construction finishes.
sample.IntPropertyreturns42.
Important detail
The chained constructor call happens before the constructor body executes. That is why constructor chaining is part of the constructor declaration, not a normal method call inside the body.
Real World Use Cases
Constructor chaining is common whenever a class can be created in multiple ways but should still follow one central initialization path.
Common scenarios
- Parsing input
- Create an object from a string, but store the parsed numeric or date value.
- Default values
- A shorter constructor fills in default configuration values.
- Convenience overloads
- Let callers pass fewer arguments while routing to a fuller constructor.
- Validation
- Convert or validate input first, then delegate to the main constructor.
- Configuration objects
- Support both simple and advanced object creation patterns.
Example: API client configuration
public class ApiClient
{
private readonly string _baseUrl;
private readonly int _timeoutSeconds;
public ApiClient(string baseUrl, int timeoutSeconds)
{
_baseUrl = baseUrl;
_timeoutSeconds = timeoutSeconds;
}
public ApiClient(string baseUrl) : this(baseUrl, 30)
{
}
}
This lets callers create an API client with a default timeout or specify one explicitly.
Real Codebase Usage
In real projects, developers usually pick one primary constructor overload that does the actual assignment and validation, then make other constructors delegate to it.
Common patterns
1. Convenience overloads
public ReportGenerator(string outputPath) : this(outputPath, false)
{
}
This avoids repeating assignments.
2. Input normalization before delegation
public Product(string priceText) : this(decimal.Parse(priceText))
{
}
The string-based constructor converts data into the real internal type.
3. Guard clauses in the main constructor
public class Person
{
private readonly string _name;
public Person(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("Name is required.", nameof(name));
_name = name;
}
public Person() : this("Unknown")
{
}
}
The validation lives in one place.
4. Reducing maintenance cost
If a class later gains another readonly field, you only update the main constructor instead of every overload.
Why teams prefer this
- Less duplicated logic
- More consistent validation
- Easier refactoring
- Better readability once you know the pattern
Common Mistakes
1. Duplicating initialization logic
Problem
public class Sample
{
private readonly int _intField;
public Sample(int theInt)
{
_intField = theInt;
}
public Sample(string theIntAsString)
{
int i = int.Parse(theIntAsString);
_intField = i;
}
}
This works, but the assignment logic is repeated.
Better
public Sample(string theIntAsString) : this(int.Parse(theIntAsString))
{
}
2. Trying to call another constructor like a method
Broken code
public Sample(string theIntAsString)
{
Sample(int.Parse(theIntAsString));
}
Constructors are not normal methods. You cannot call them inside the body like this.
Fix
Use : this(...) in the constructor declaration.
3. Using a helper method to assign a readonly field later
Broken idea
private void Init(int value)
{
_intField = value;
}
This may fail because readonly fields must be assigned during declaration or construction, not from arbitrary methods.
Fix
Put the assignment in one constructor and chain to it.
4. Forgetting parse errors
Risk
public Sample(string theIntAsString) : this(int.Parse(theIntAsString))
{
}
If the string is not a valid integer, int.Parse throws an exception.
Safer alternative
public Sample(string theIntAsString) : this(ParseOrThrow(theIntAsString))
{
}
private static int ParseOrThrow(string value)
{
if (!int.TryParse(value, out int result))
throw new ArgumentException("Value must be a valid integer.", nameof(value));
return result;
}
5. Creating constructor cycles
Broken code
public Sample(int x) : this(x.ToString())
{
}
public Sample(string s) : this(int.Parse(s))
{
}
These constructors call each other forever, which is not allowed.
Fix
Choose one constructor as the main one and have the others delegate to it.
Comparisons
| Concept | What it does | Best use case |
|---|---|---|
this(...) | Calls another constructor in the same class | Reusing initialization logic across overloads |
base(...) | Calls a constructor in the parent class | Initializing inherited state |
| Helper method | Moves repeated logic into a normal method | Shared behavior that does not depend on constructor-only assignment |
| Field initializer | Assigns a field where it is declared | Simple default values |
this(...) vs helper method
| Feature | this(...) | Helper method |
|---|---|---|
Works naturally with readonly fields | Yes | Often not suitable for assignment |
| Avoids duplicated constructor logic | Yes | Sometimes |
| Runs during object construction | Yes | Not always in the right way |
| Good for overload delegation | Yes | No |
this(...) vs base(...)
- Use
this(...)when calling another constructor in the same class. - Use
base(...)when calling a constructor from the parent class.
Example:
public class Animal
{
public Animal(string name) { }
}
public class Dog : Animal
{
public Dog() : base("Dog")
{
}
}
Cheat Sheet
Quick syntax
public MyClass(string text) : this(int.Parse(text))
{
}
Rules
- Use
: this(...)to call another constructor in the same class. - The chained constructor call appears in the constructor declaration, not in the body.
- One constructor should usually be the main constructor.
- Other constructors should prepare values and delegate to it.
- This is a good pattern for initializing
readonlyfields.
Example
public class Sample
{
private readonly int _intField;
public Sample(int theInt)
{
_intField = theInt;
}
public Sample(string text) : this(int.Parse(text))
{
}
}
Common pitfalls
- Do not try to call a constructor like a normal method.
- Do not create circular constructor chains.
- Be careful with parsing methods that can throw exceptions.
- Keep validation in one main constructor when possible.
Related syntax
this(...)= same class constructorbase(...)= parent class constructor
FAQ
How do you call one constructor from another in C#?
Use : this(...) after the constructor signature.
public Sample(string text) : this(int.Parse(text))
{
}
Can readonly fields be assigned through constructor chaining?
Yes. If the field is assigned in the constructor that gets called through this(...), it is still considered valid constructor-time initialization.
Should every constructor assign fields directly?
Not usually. A common pattern is to have one main constructor do the assignments, while other constructors delegate to it.
What is the difference between this(...) and base(...) in C#?
this(...)calls another constructor in the same class.base(...)calls a constructor in the parent class.
Can I call a constructor from inside another constructor body?
No. In C#, constructor chaining must be declared with : this(...) or : base(...).
What happens if int.Parse fails in a chained constructor?
It throws an exception before object construction completes. If the input may be invalid, consider using int.TryParse with explicit error handling.
Is constructor chaining good practice?
Yes, when multiple constructors share initialization logic. It reduces duplication and keeps object creation consistent.
Mini Project
Description
Build a small Temperature class that can be created either from a numeric Celsius value or from a string such as "25". This demonstrates constructor chaining, avoids duplicated initialization logic, and shows how to keep readonly field assignment in one place.
Goal
Create a class with multiple constructors where one constructor parses input and delegates to the main constructor.
Requirements
- Create a
Temperatureclass with a privatereadonlyfield for Celsius. - Add one constructor that accepts a
double. - Add one constructor that accepts a
stringand converts it to adouble. - Use constructor chaining so the field is assigned in only one constructor.
- Expose the stored value through a read-only property.
- Print results from both constructors in a small demo program.
Keep learning
Related questions
AddTransient vs AddScoped vs AddSingleton in ASP.NET Core Dependency Injection
Learn the differences between AddTransient, AddScoped, and AddSingleton in ASP.NET Core DI with examples and practical usage.
Best Way to Repeat a Character in C#: Building Repeated Strings Efficiently
Learn the best way to repeat a character in C#, compare StringBuilder, string concatenation, and simpler built-in options.
C# Access Modifiers and static: public, private, protected, and Defaults
Learn how C# public, private, protected, and default access control visibility, and how static differs from instance members.