0Pricing
C# Academy · レッスン

不変オブジェクトのパターン

作成後に決して変化しないオブジェクトを設計します。

「不変オブジェクトのパターン」はCoddyKit上の無料C# Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはC# Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 C# Academyコースには全4レッスンが含まれています。

不変オブジェクトを設計する

不変オブジェクトは構築後に変化しません。不変性によって、共有された変更可能な状態に関するさまざまなバグをなくし、オブジェクトを安全に受け渡したりキャッシュしたりできます。

get 専用プロパティ

最も単純な不変プロパティは get 専用で、コンストラクターから一度だけ設定します。

using System;

class Point {
    public int X { get; }
    public int Y { get; }
    public Point(int x, int y) { X = x; Y = y; }
}

var p = new Point(3, 4);
Console.WriteLine(p.X + "," + p.Y); // 3,4

初期化子構文に init を使う

不変性と便利なオブジェクト初期化子構文を両立したい場合は、initプロパティを使います。

using System;

class Color {
    public int R { get; init; }
    public int G { get; init; }
    public int B { get; init; }
}

var c = new Color { R = 255, G = 128, B = 0 };
Console.WriteLine(c.R + "," + c.G + "," + c.B); // 255,128,0

必須フィールドに required を使う

required + initを組み合わせると、重要なフィールドの設定漏れと、設定後の変更を防げます。

using System;

class Money {
    public required decimal Amount { get; init; }
    public required string Currency { get; init; }
}

var m = new Money { Amount = 9.99m, Currency = "USD" };
Console.WriteLine(m.Amount + " " + m.Currency); // 9.99 USD

変更する代わりに新しいオブジェクトを返す

不変型では、「変更」操作を元のインスタンスに手を加えず、新しいインスタンスを返すメソッドとして公開します。

using System;

class Point {
    public int X { get; init; }
    public int Y { get; init; }
    public Point Move(int dx, int dy) => new Point { X = X + dx, Y = Y + dy };
}

var a = new Point { X = 1, Y = 1 };
var b = a.Move(2, 3);
Console.WriteLine(a.X + "," + a.Y + " -> " + b.X + "," + b.Y); // 1,1 -> 3,4

不変コレクション

コレクション用のフィールドには、不変または読み取り専用のコレクションを格納し、オブジェクトを通じて内容が変更されないようにします。

using System;
using System.Collections.Immutable;

class Team {
    public ImmutableList<string> Members { get; init; } = ImmutableList<string>.Empty;
}

var t = new Team { Members = ["Ada", "Lin"] };
var t2 = new Team { Members = t.Members.Add("Sam") };
Console.WriteLine(t.Members.Count + " " + t2.Members.Count); // 2 3

防御的コピー

変更可能なコレクションを受け取る必要がある場合は、受け取る際にコピーして、外部の変更が内部に影響しないようにします。

using System;
using System.Collections.Generic;
using System.Linq;

class Snapshot {
    private readonly int[] data;
    public Snapshot(IEnumerable<int> source) => data = source.ToArray();
    public IReadOnlyList<int> Data => data;
}

var list = new List<int> { 1, 2, 3 };
var snap = new Snapshot(list);
list.Add(4); // does not affect snap
Console.WriteLine(snap.Data.Count); // 3

値の等価性

不変オブジェクトでは、値に基づく等価性が求められることがよくあります。同じデータを持つ2つのインスタンスを等しいとみなす仕組みです。レコードでは標準で利用できますが、クラスではオーバーライドが必要です。

using System;

record Coord(int X, int Y);

Console.WriteLine(new Coord(1, 2) == new Coord(1, 2)); // True

自然に得られるスレッドセーフ性

不変オブジェクトは決して変化しないため、ロックなしで共有しても本質的にスレッドセーフです。

using System;

class ReadonlyConfig {
    public required string Env { get; init; }
}

var cfg = new ReadonlyConfig { Env = "prod" };
// safe to read from many threads without synchronization
Console.WriteLine(cfg.Env); // prod

readonly フィールドと構造体

readonlyフィールドとreadonly structを使うと、値型の不変性をフィールドレベルで強制できます。

using System;

readonly struct Vector {
    public readonly double X, Y;
    public Vector(double x, double y) { X = x; Y = y; }
    public double Length => Math.Sqrt(X * X + Y * Y);
}

Console.WriteLine(new Vector(3, 4).Length); // 5

まとめて実装する

required、init、値の等価性、非破壊的な更新メソッドを組み合わせた、完全に不変な型です。

using System;

record Account(string Id, decimal Balance) {
    public Account Deposit(decimal amount) => this with { Balance = Balance + amount };
}

var a = new Account("A1", 100m);
var b = a.Deposit(50m);
Console.WriteLine(a.Balance + " -> " + b.Balance); // 100 -> 150

簡単な確認

不変オブジェクトを更新する原則を確認してください。

まとめ

不変オブジェクトの設計パターンを学びました。

  • 必須データには get 専用またはinitプロパティとrequiredを使います。
  • 変更は、新しいインスタンスを返すメソッドとしてモデル化します。
  • 不変コレクション、または防御的にコピーしたコレクションを格納します。
  • レコードは値の等価性とwithによるコピーを提供し、不変性によってスレッドセーフ性が得られます。

よくある質問

「不変オブジェクトのパターン」レッスンは無料ですか?

はい。「不変オブジェクトのパターン」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、C# Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 C# Academyコースには全4レッスンが含まれています。

「不変オブジェクトのパターン」で何を学びますか?

作成後に決して変化しないオブジェクトを設計します。 ブラウザで直接実行するハンズオンコードでC# Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

C# Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのC# Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。

「不変オブジェクトのパターン」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このC# Academyレッスンでコードを書いて実行できますか?

はい。すべてのC# Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. init専用setter
  2. required修飾子
  3. 不変オブジェクトのパターン
  4. レコードのwith式
← C# Academyに戻る