C#のreadonlyの使い方と注意点を解説します!

- システム
エンジニア - C#のreadonlyの注意点には、どのようなものがあるのでしょうか?
- プロジェクト
マネージャー - ローカル変数の宣言には使えないので注意が必要です。
C#のreadonlyとは?
C#にはreadonlyというクラスフィールド(クラスのメンバ変数)の修飾子があります。これを使いこなすことで、バグの少ない安全なプログラムをコーディングすることができます。それでは具体的な使い方を説明しましょう。以下がサンプルです。
class Human
{
public String name;
public int age;
// コンストラクタ
public Human(String n, int a)
{
name = n;
age = a;
}
}
class Program
{
static Human h;
static void Main(string[] args)
{
h = new Human(“山田太郎”, 20);
h.age = 30; // 年齢を修正
}
}
readonlyで読み取り専用にできる
上のサンプルはMainメソッド内で、nameとageというクラスフィールドを持つHumanクラスをnewで生成し、ageの値を後から変更しています。もし、このnameとageを後から変更できないようにしたい場合はどうすれば良いのでしょうか。
ここで役立つのがreadonlyです。Humanクラスを以下のように変更してください。
class Human
{
public readonly String name; // readonlyを付加
public readonly int age; // readonlyを付加
// コンストラクタ
public Human(String n, int a)
{
name = n;
age = a;
}
}
readonlyでコンストラク内のみ値が変更可能になる
上のようにクラスフィールドにreadonlyを追加することで読み取り専用になります。もし以下のようにすると、
h = new Human(“山田太郎”, 20); // これは問題ない
h.name = “山田花子”; // これはエラー
h.age = 30; // これもエラー
2、3行目は「読み取り専用フィールドを割り当てることはできません」と言うエラーになります。これで変更されたくないフィールドを保護することができます。
なお、newする時のコンストラクタ内での代入はエラーになりません。readonlyのフィールドは、newで呼ばれるコンストラクタ内だけ自由に値を変更することができます。
readonlyはクラス型フィールドにも使用できる
readonlyはクラス型のフィールドにも使用できます。以下をご覧ください。
class Human
{
public String name;
public int age;
public Human(String n, int a)
{
name = n;
age = a;
}
}
class Program
{
static readonly Human h = new Human(“山田太郎”, 20); // readonlyで宣言
static void Main(string[] args)
{
h.name = “山田花子”; // 変更可能
h.age = 30; // 変更可能
h = new Human(“佐藤一郎”, 35); // エラー
}
}
Human型のフィールドのhはreadolyのため、新たにnewするとエラーになります。ただし、hのクラスフィールドのnameやageは、hがreadonlyでも変更できます。
クラスフィールドを変更できないようにするには、各フィールドをreadonlyにするか、getのみのプロパティにする必要があります。
readonlyで出来ないこと
便利なreadonlyですが制約もあります。ローカル変数の宣言にreadonlyは使えません。メソッドの中で以下のようにするとエラーになります。
readonly int value = 100;
このような場合は、constを使用します。
const int value = 100;
これでvalueは常に100になります。なぜ、C#には似たような機能のconstとreadonlyがあるのかというと、それはconstは静的でreadonlyは動的という使い方の違いがあるからです。
別の言い方をすると、上の例でvalueはコンパイル時に100という数値に置き換えられますが、readonlyの変数は読み取り専用の変数として扱われます。
constでは出来ないこと
constにもreadonlyと比べて出来ないことがあります。まず、constの変数は宣言時に必ず値を代入して定数とする必要があります。readonlyのように後からコンストラクタ内で値を設定する、ということができません。
また、newをするクラス型の変数にもconstは使えません。ただしnewをせずnullを代入して宣言する場合はconstにできます。nullの定数を宣言しても、使い道はあまりありません。
readonlyとconstを上手く使い分けよう
上で説明したconstで出来ないことの実例は以下になります。
const int value; // 値を代入してないのでエラー
const Human const_h = new Human(“山田太郎”, 20); // newは出来ないのでエラー
const Human null_h = null; // これはOK。ただし使い道は無い
const変数は宣言時に値が確定してなければならないということです。クラス型の変数にはアドレスが入るため、newする時のメモリの状況によって値が変化してしまいます。
元々、constはC言語など古くからある定数を宣言するための機能でした。C#のreadonlyは定数ではないクラスフィールドをreadonlyにする目的で、後から登場しました。両方を上手く使い分けましょう。
readonlyは構造体の場合はクラスと動作が変わる
C#にはクラスに似た機能の構造体、structがあります。readonlyはstructの場合はクラスと動作が変わります。以下はそれを説明するためのサンプルです。
// 構造体を宣言
struct Human
{
public String name;
//コンストラクタ
public Human(string s)
{
name = s;
}
public void setName(string s)
{
name = s;
}
}
class Program
{
static readonly Human h1 = new Human(“山田太郎”); // readonlyで宣言
static void Main(string[] args)
{
h1.setName(“佐藤一郎”);
Console.WriteLine(h1.name); // 山田太郎のまま
Human h2 = h1; // 非readonlyのh2に代入
h2.setName(“鈴木花子”);
Console.WriteLine(h2.name); // 鈴木花子に変わる
}
}
構造体へのreadonlyの使い方
上のサンプルを実行すると、
山田太郎
鈴木花子
と表示されます。なぜ1つ目は佐藤一郎にならないのでしょうか。それは、h1はreadonlyのため、setNameが呼ばれた時に実体とは別のnameが複製されて、そこに”佐藤一郎”が代入されたからです。よってreadonlyの場合は構造体の変数は変更されません。
しかし、この場合ミスが起こりやすいです。そこでC#のVer. 8.0からは構造体のメソッドにreadonlyを付けられるようになりました。上の例では、
readonly public void setName(string s)
{
name = s; // エラーになる
}
とすることができます。これでname = s;がエラーになるので間違いは起こりません。nameはコンストラクタで初期化して、他のメソッドにはreadonlyを付けて変更できないようにするとよいでしょう。
参照変数のrefにもreadonlyを付けられる
C#にはrefという、他のメソッドに変数を参照で渡すキーワードがあります。C#のVer. 7.2からはこれにreadonlyを使用できます。サンプルは以下です。
static void refTest(ref int val)
{
ref readonly int r_val = ref val; // 読み取り専用の参照変数
Console.WriteLine(r_val);
val++;
}
static void Main(string[] args)
{
int a = 3;
refTest(ref a);
Console.WriteLine(a);
}
ref readonlyで分かりやすいソースコードになる
上のサンプルを実行すると、
3
4
と表示されます。refTestに渡した変数int aは、refTest内ではref int valという参照変数として扱われます。refTestではr_valという読み取り専用の参照変数にvalを代入しています。それを表示していますが、3のままです。r_valを変更しようとするとreadonlyのためエラーになります。
refTestではvalが加算されますが、これはaの参照変数なのでaが加算されます。そのためaを表示すると、1増えて4になります。
参照変数を使用するメソッド内では、ref readonlyを使うことで読み取り専用であることを明示できてわかりやすくなるでしょう。
- システム
エンジニア - C#のreadonlyはさまざまなことができるのですね。
- プロジェクト
マネージャー - そうですね。バグが少ないソースコードを記述できるようになるので上手に活用しましょう!
C#のreadonlyの使い方を知ろう!
C#のreadonlyについて解説しましたが、いかがでしたか。読み取り専用にしたい変数にreadonlyを使えば、間違えて値を変更することが無くなるのでバグが少ないソースコードを記述できるようになります。
安全なC#プログラミングを実現するために、ぜひreadonlyを活用してください。
FEnet.NETナビ・.NETコラムは株式会社オープンアップシステムが運営しています。
株式会社オープンアップシステムはこんな会社です
秋葉原オフィスには株式会社オープンアップシステムをはじめグループのIT企業が集結!
数多くのエンジニアが集まります。

-
スマホアプリから業務系システムまで
スマホアプリから業務系システムまで開発案件多数。システムエンジニア・プログラマーとしての多彩なキャリアパスがあります。
-
充実した研修制度
毎年、IT技術のトレンドや社員の要望に合わせて、カリキュラムを刷新し展開しています。社内講師の丁寧なサポートを受けながら、自分のペースで学ぶことができます。
-
資格取得を応援
スキルアップしたい社員を応援するために資格取得一時金制度を設けています。受験料(実費)と合わせて資格レベルに合わせた最大10万円の一時金も支給しています。
-
東証プライム上場企業グループ
オープンアップシステムは東証プライム上場「株式会社オープンアップグループ」のグループ企業です。
安定した経営基盤とグループ間のスムーズな連携でコロナ禍でも安定した雇用を実現させています。
株式会社オープンアップシステムに興味を持った方へ
株式会社オープンアップシステムでは、開発系エンジニア・プログラマを募集しています。
年収をアップしたい!スキルアップしたい!大手の上流案件にチャレンジしたい!
まずは話だけでも聞いてみたい場合もOK。お気軽にご登録ください。


C#新着案件New Job
-
システム開発/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(新宿駅) -
システム開発/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(新宿駅) -
デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円神奈川県横浜市(桜木町駅) -
デバック、テスト項目の作成/神奈川県横浜市/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円神奈川県横浜市(桜木町駅) -
基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代前半の方活躍中/経験1年以上の方活躍中】/在宅勤務
月給29万~34万円東京都新宿区(西新宿駅) -
基幹システム開発導入/東京都新宿区/【WEB面談可/C#経験者/20代後半~40代の方活躍中/経験年数不問】/在宅勤務
月給41万~50万円東京都新宿区(西新宿駅)