C#のconstとreadonlyの違いを徹底解説!正しい使い分けのポイント
C#には、一度宣言したら変更できない不変(イミュータブル)な値を定義するためのキーワードとして、「const」と「readonly」の2つが用意されています。どちらも定数のような役割を持ちますが、その挙動や適用できる場面には重要な違いがあります。本記事では、それぞれの特徴と使い分けのポイントをコード例とともに詳しく解説します。
constキーワードとは
「const」修飾子は、コンパイル時に値が確定し、以後一切変更されない定数を宣言するために使用します。C#では、組み込み型(int、double、stringなど)のみをconstとして宣言でき、クラスや構造体などのユーザー定義型をconstにすることはできません。また、メソッド、プロパティ、イベントといったクラスメンバーを定数として扱うこともできません。
constで宣言する定数は、宣言時に必ず初期化する必要があります。
class Period{
public const int hours = 12;
public const int minutes = 60;
}constフィールドには、private、public、protected、protected internal、private protectedなど、任意のアクセス修飾子を付けることができます。
さらに重要な点として、constは暗黙的にstaticであるという特性があります。つまり、定数の値はクラスのすべてのインスタンスで共通になります。staticキーワードを明示的に付ける必要はなく、むしろ付けることはできません。また、インスタンス変数からはアクセスできず、必ずクラス名を通じて参照します。
readonlyキーワードとは
「readonly」修飾子を付けたフィールドは、宣言時またはコンストラクター内でのみ代入可能です。クラスのインスタンスが生成された後は、readonlyフィールドの値を変更することはできません。
readonlyフィールドが値型の場合、そのフィールドは完全に不変になります。一方、参照型の場合は挙動に注意が必要です。変数自体への再代入はできませんが、参照先のオブジェクトの中身(データ)は変更可能です。ただし、参照先を別の新しいオブジェクトに付け替えることはできません。
class Person{
private readonly string _title;
private readonly string _skill;
public Person(string title, string skill){
_title = title;
_skill = skill;
}
}readonlyフィールドは、フィールド宣言時と各コンストラクター内で複数回代入できます。また、使用されるコンストラクターによって異なる値を持つことも可能です。これはconstでは実現できない柔軟性です。
アセンブリをまたいだ場合の大きな違い
constとreadonlyの最も重要な違いは、あるアセンブリで宣言された定数・readonlyフィールドを、別のアセンブリから利用してコンパイルするときに現れます。
constの場合: 定数の値は「検索置換」のように、利用側アセンブリの中間言語(IL)に直接埋め込まれます(ベイクされます)。そのため、元の定数の値を更新しても、利用側アセンブリを再コンパイルしない限り古い値が使われ続けます。
readonlyの場合: 値はメモリ上の場所への参照として扱われ、ILに埋め込まれません。そのため、元のアセンブリ側で値を更新すれば、利用側アセンブリは再コンパイルなしで新しい値を取得できます。ライブラリ開発などでは、この点がreadonlyを選ぶ大きな理由になります。
サンプルコード
using System;
class Program{
static void Main(){
Console.WriteLine(Period.HOURS);
var person = new Person("John", "Programmer");
person.Print();
}
}
class Period{
public const int HOURS = 12;
public const int MINUTES = 60;
}
class Person{
private readonly string _title;
private readonly string _skill;
public Person(string title, string skill){
_title = title;
_skill = skill;
}
public void Change(string skill){
// エラー: readonly フィールドには代入できません
// this._skill = skill;
}
public void Print(){
Console.WriteLine($"{_title}: {_skill}");
}
}
実行結果
12
John: Programmer
まとめ
constは「コンパイル時に確定する真の定数」であり、数学定数や固定設定値など、絶対に変わらない値に適しています。一方、readonlyは「生成後に変更されないフィールド」であり、コンストラクターでの初期化や実行時に決まる値、アセンブリ間で安全に共有したい値に向いています。特にライブラリやDLLとして公開するコードでは、再コンパイル問題を避けるためにreadonlyを選ぶのが一般的なベストプラクティスです。
-
【C/C++】const int*、const int* const、int const* の違いをわかりやすく解説
C言語やC++では、ポインタとconst修飾子の組み合わせ方によって、複数の異なる変数宣言が存在します。「const int*」「const int* const」「int const*」など、一見よく似たこれらの宣言の違いを正確に理解することは、安全でバグの少ないコードを書くうえで非常に重要です。本記事では、これら3つの宣言の違いを、複雑な宣言を読み解く際に役立つ「時計回り/らせんルール(Clockwise/Spiral Rule)」にも触れながら、コード例とともに分かりやすく解説します。時計回り/らせんルールとは宣言の中心にある識別子から出発し、時計回りに記号をなぞっていくことで、cons
-
C#におけるstringとStringの違いは何ですか?
C#のstringとStringの違いC#プログラミングにおいて、stringとStringはどちらも同じ型を指しますが、その扱いには微妙な違いがあります。Stringは.NET FrameworkのクラスであるSystem.Stringを直接表すものであり、一方、stringはC#言語が用意しているSystem.Stringのエイリアス(別名)です。つまり、両者はコンパイル後にまったく同じものとして扱われます。基本的な使い方の例string str = Welcome!;このように文字列変数を宣言する際は、通常小文字のstringを使用します。使い分けの目安厳密なルールはありませんが、一般的