Understanding Init-Only Properties in C#

Understanding Init-Only Properties in C#

Introduction

C# 9.0 introduced a new feature called init-only properties, enhancing the language’s support for immutable data structures.

These properties allow for more concise and safe object initialisations, and are particularly useful in scenarios where immutability is a key concern, such as in multi-threaded applications.

What are Init-Only Properties?

Init-only properties in C# are properties that can only be set during object initialization. They are a part of the record and object initializer syntax enhancements in C# 9.0.

These properties provide a way to make individual properties read-only after the object construction phase, thereby ensuring immutability.

How Init-Only Properties Work

  • Syntax: Init-only properties are declared using the init accessor instead of the set accessor.
  • Initialization: They can be set using an object initializer or in the constructor, but not afterwards.

Example of Init-Only Properties

Here’s a simple example:

public class Person 

    public string FirstNamegetinit; } 
    public string LastNamegetinit; } 

    
// Usage 
var personnew Person { FirstName"John", LastName"Doe"}; 

// person.FirstName = "Jane"; 
// This line would result in a compile-time error

In this example, FirstName and LastName are init-only properties. They can be set when the Person object is created but are read-only afterwards.

Advantages of Using Init-Only Properties

  1. Immutability: They help in creating immutable objects, which are easier to reason about and safer to use in concurrent environments.
  2. Safety: By preventing modification after initialisation, init-only properties reduce the risk of unintended side effects.
  3. Clarity: The intent of immutability is clearly communicated in the code.

Use Cases

  • Domain Models: In domain-driven design, entities and value objects can benefit from immutability.
  • Data Transfer Objects (DTOs): DTOs often carry data that should not change once set.
  • Configuration Objects: Configuration data, which is read-only after the application starts, is another ideal use case.

Advanced Scenarios

  1. Combining with Other Features: Init-only properties can be combined with features like non-nullable reference types to create robust and safe domain models.
  2. Use in Data Transfer Objects (DTOs): They are ideal for use in DTOs, where immutable data structures can help prevent inadvertent changes and bugs.
  3. Deconstructors in Records: When used in records, init-only properties work well with deconstructors, making it easy to decompose records into variables.

Comparison with Records

Similarities

  • Promote Immutability: Both init-only properties and records are designed to create immutable data structures.
  • Simplify Object Initialization: They provide cleaner syntax for object initialization.

Differences

  • Flexibility vs. Specialization: Init-only properties are more flexible as they can be used in any class, whereas records are specialized types with additional features like value-based equality.
  • Equality Comparison: Records come with built-in value-based equality checks, whereas classes with init-only properties still use reference-based equality unless overridden.
  • Use Cases: Init-only properties are ideal for adding immutability to existing classes or when partial immutability is required. Records are best suited for simple, immutable data carriers and can be more concise for this purpose.
  • Syntax and Features: Records have additional syntax features like with expressions and built-in deconstructors, which are not available with init-only properties.

Best Practices

  • Clearly Define Immutable Types: Use init-only properties to clearly express the intent of immutability in your classes or records.
  • Avoid Public Setters for Mutability: Refrain from using public setters alongside init-only properties unless specific mutable properties are necessary.
  • Evaluate Use Cases: Consider using init-only properties in scenarios where object state shouldn’t change after initialization, like in configurations or entity representations.

Conclusion

Init-only properties in C# are a powerful feature for developers looking to create immutable types more naturally and concisely. They enhance the language’s capability to express immutable data constructs, aligning with modern programming practices that emphasize immutability for safer and more predictable code.

By adopting init-only properties, C# developers can ensure their object models are correctly and clearly defined as immutable where appropriate.

While init-only properties and records in C# both facilitate the creation of immutable types, they cater to different scenarios. Init-only properties offer a way to introduce immutability into any class, providing flexibility.

Records, on the other hand, are a more comprehensive solution for creating data-centric types with additional features like value-based equality and with expressions. The choice between the two depends on the specific requirements of the application and the preferred programming style.

Stephen

Hi, my name is Stephen Finchett. I have been a software engineer for over 30 years and worked on complex, business critical, multi-user systems for all of my career. For the last 15 years, I have been concentrating on web based solutions using the Microsoft Stack including ASP.Net, C#, TypeScript, SQL Server and running everything at scale within Kubernetes.