読み取り専用なフィールドを生成する(const VS readonly)

プログラミングC# 第6版 3.2.6


constを使うと書き換え不可な読み取り専用フィールドを生成することができます。これはC++でも同じですね。

class CSample {
    public const int foo = 1;
}

一方readonlyを使っても読み取り専用フィールドを生成することができます。

class CSample {
    public const int foo = 1;
    public readonly int bar = 2;
}

では一体両者の違いとは?

まずは一つ目の違い。

constはクラスにひとつのデータとして静的に生成されます、一方readonlyはオブジェクト毎に生成されます。

よってフィールドへのアクセスの方法が以下のように異なります。

using System;

class CSample {
    public const int foo = 1;
    public readonly int bar = 2;
}

class Program {
    static void Main () {
        CSample obj = new CSample();
        
        // constは静的に生成されてるのでクラス名からしか取れない
        Console.WriteLine(CSample.foo);
        //Console.WriteLine(obj.foo); // コンパイルエラー
        
        // readonlyはオブジェクト毎に生成されるのでオブジェクトからしか取れない
        Console.WriteLine(obj.bar);
        //Console.WriteLine(CSample.bar); // コンパイルエラー
    }
}
$ main
1
2

そして二つ目の違い。これがconstとreadonlyの決定的に違う部分ですね。

constは定義時に値を決めたらその後書き換えることができないという仕様ですが、readonlyは定義時とコンストラクタ内で値を書き換えることが許可されています。

なのでreadonlyはオブジェクトが生成された時点で値を設定し、以後は変更できない値として扱うことができるということです。

using System;

class CSample {
    public readonly int bar;
    
    public CSample (int val) {
        // コンストラクタ内なので書き換えOK
        bar = val;
    }
    
    public void baz () {
        // コンストラクタ以外での書き換えはコンパイルエラー
        //bar = 10;
    }
}

class Program {
    static void Main () {
        CSample obj = new CSample(5);
        
        Console.WriteLine(obj.bar);
    }
}
$ main
5

これはかなり便利ですね。オブジェクト毎にconstなフィールドを簡単に生成できます。色々使い道がありそうですね。

静的な値であればC++でも似たようなことをテンプレートを使えばできますが、動的な値でも可能というのが素晴らしいです。