[C#] Defining Immutable Objects Using Init-Only Setters

Introduced in C# 9.0, init accessors (init-only setters) allow you to easily define properties that can only be set during object initialization and become immutable (read-only) afterwards.

Previously, creating immutable objects required combining “read-only properties (get-only)” with “constructors taking arguments.” However, by using the init accessor, you can maintain the flexible syntax of object initializers (new Class { Prop = val }) while enhancing safety.

In this article, I will explain the implementation and behavior of init accessors using a class that handles book data as an example.

目次

Table of Contents

  1. Implementation Example: Book Class Immutable After Initialization
  2. Explanation
  3. Summary

Implementation Example: Book Class Immutable After Initialization

In the following code, the Book class uses init for its properties. This allows values to be set during instance creation, but subsequent assignment operations will result in a compile error, preventing data modification.

using System;

namespace InitAccessorExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 1. Setting via object initializer (Allowed)
            // Properties with init accessors can be set at this timing
            var book = new Book
            {
                Title = "The Tale of Genji",
                Author = "Murasaki Shikibu"
            };

            Console.WriteLine($"Registration Complete: {book.Title} (Author: {book.Author})");

            // 2. Modification after initialization (Not allowed)
            // Compile Error: Init-only property or read-only property cannot be assigned to
            // book.Author = "Sei Shonagon"; 
            
            // Note: Attempting normal assignment shows an error in the editor,
            // eliminating the risk of accidental data modification.
        }
    }

    public class Book
    {
        // Use 'init' instead of 'set'
        public string Title { get; init; }
        public string Author { get; init; }

        // Note: Traditional syntax (set) allows modification at any time
        // public string Description { get; set; }
    }
}

Explanation

1. Role of the init Accessor

You use the init keyword instead of set in the property definition.

public string Author { get; init; }

This ensures that the property can only be set at the following times:

  • Inside the constructor
  • In an object initializer (new Book { ... })
  • When copying using a with expression

2. Reducing Constructor Boilerplate

In the previous method (getter-only + constructor), every time a property was added, the constructor arguments had to be modified, leading to bloated code.

By using init accessors, you can keep the parameterless constructor (default constructor) and allow the caller to selectively initialize only the necessary properties, keeping the code clean.


Summary

The init accessor is an excellent feature that balances data robustness (Immutability) with initialization flexibility.

  • Use Case: Data models that should not be changed after creation, such as master data or configuration values.
  • Benefit: Prevents unintended value modification at compile time.

For classes with the characteristic of “create once, never change,” it is highly recommended to actively use init instead of set.

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次