Init-only setters in C# 9 solve an age-old problem: how do you create immutable objects while still using the convenient object initializer syntax? Previously, you had to choose between constructor-based initialization (verbose) or public setters (mutable). Init-only setters give you both convenience and immutability.
The Problem
// Old approach 1: Mutable (bad for immutability)
public class Person
{
public string Name { get; set; } // Anyone can change anytime
}
var p = new Person { Name = "John" };
p.Name = "Changed"; // Oops, mutated!
// Old approach 2: Constructor only (inconvenient for many properties)
public class Person
{
public string Name { get; }
public string Email { get; }
public DateTime DateOfBirth { get; }
public string Address { get; }
public Person(string name, string email, DateTime dob, string address)
{
Name = name;
// ...constructor gets long and unwieldy
}
}
The Solution: Init-Only Setters
public class Person
{
public string Name { get; init; }
public string Email { get; init; }
public DateTime DateOfBirth { get; init; }
public string Address { get; init; }
}
// Can use object initializer
var person = new Person
{
Name = "John",
Email = "john@example.com",
DateOfBirth = new DateTime(1990, 1, 1),
Address = "123 Main St"
};
// But cannot modify after initialization
person.Name = "Jane"; // Compile error!
Init in Derived Classes
Init-only properties can be set in derived class constructors too:
public class Employee : Person
{
public string EmployeeId { get; init; }
public Employee()
{
// Can set base class init properties
Name = "Default";
}
}
var emp = new Employee
{
Name = "John", // Still works
EmployeeId = "E001"
};
Required Properties (C# 11 Preview)
Looking ahead, C# 11 will add required modifier to ensure init properties must be set:
public class Person
{
public required string Name { get; init; } // Must be set
public string? Nickname { get; init; } // Optional
}
var p = new Person(); // Error: Name is required
var p = new Person { Name = "John" }; // OK
Combining with Records
Records use init-only setters by default for positional properties, but you can also define additional init properties:
public record Person(string FirstName, string LastName)
{
// Additional init-only property
public string? MiddleName { get; init; }
}
var person = new Person("John", "Doe") { MiddleName = "William" };
Key Takeaways
- Init-only setters allow object initializer syntax with immutability
- Property can only be set during object initialization
- Works with derived classes and records
- Combine with
required(C# 11) for mandatory properties
References
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.