C# コンパイラエラー CS0191 の原因と対処法について解説
CS0191は、C#で読み取り専用のプロパティやフィールドに値を割り当てようとした場合に発生するエラーです。
読み取り専用のメンバーは、宣言時またはコンストラクタ内でのみ初期化することが可能なため、他の場所で変更を試みるとエラーとなります。
エラー解消のためは、値の設定タイミングを見直してください。
CS0191 エラーの基本情報
エラーメッセージの詳細
C# のコンパイラが出力する CS0191 エラーは、readonly
キーワードが付与されたフィールドに対して不適切な割り当てが行われた場合に発生します。
一般的には、readonly
フィールドは宣言時またはコンストラクター内でのみ初期化が許可されているため、他の場所での代入を試みるとこのエラーが発生します。
エラーメッセージには「プロパティまたはインデクサー ‘フィールド名’ は読み取り専用なので、割り当てることはできません」という内容が表示されます。
発生条件とエラー原因
CS0191 エラーが発生する主な条件は以下の通りです。
readonly
フィールドに、宣言時またはコンストラクター以外の場所から代入しようとした場合。readonly
フィールドがstatic
である場合、対応する静的コンストラクターまたは宣言時に初期化しないとエラーとなる場合があります。
これらの条件により、readonly
フィールドはインスタンス生成時または型が初期化されるときに、確実に初期化されることが保証される仕組みになっています。
エラー発生の具体的なケース
インスタンスフィールドの初期化制約
インスタンスフィールドに対しては、宣言時またはインスタンスコンストラクター内で初期化を行うことが許可されています。
それ以外のメソッド内で代入を試みると、CS0191 エラーが発生します。
例えば、以下のようなコードでは、TestInt
をメソッド内で再度代入しているためエラーとなります。
静的フィールドと静的コンストラクターの関係
静的フィールドの特性
static
フィールドは、クラス全体で共有されるため、インスタンス生成前に初期化される必要があります。
そのため、readonly
な static
フィールドは、宣言時または静的コンストラクター内でのみ初期化可能です。
静的コンストラクターの役割
静的コンストラクターはクラスが最初に使用される際に自動で呼び出され、static
フィールドの初期化を行います。
readonly
な static
フィールドもこの初期化の対象となり、インスタンスメソッド内で代入するのではなく、静的コンストラクター内で設定する必要があります。
不適切なコード例
以下は、CS0191 エラーが発生する不適切な例です。
この例では、TestInt
をメソッド内で再度代入しているため、コンパイル時にエラーとなります。
using System;
class MyClass
{
public readonly int TestInt = 6; // 宣言時の初期化はOK
public MyClass()
{
TestInt = 11; // コンストラクター内での初期化はOK
}
public void TestReadOnly()
{
TestInt = 19; // ここで CS0191 エラーが発生します
}
public static void Main()
{
// インスタンスの生成およびメソッド呼び出しはコメントアウトしています
// MyClass instance = new MyClass();
// instance.TestReadOnly();
Console.WriteLine("不適切なコード例のため、実行していません");
}
}
不適切なコード例のため、実行していません
対処法の具体例
宣言時による初期化方法
readonly
フィールドは、宣言時に初期化することで CS0191 エラーを回避することができます。
以下は、宣言時に初期化した例です。
using System;
class MyClass
{
public readonly int TestInt = 6; // 宣言時に初期化しているので問題ありません
public static void Main()
{
MyClass instance = new MyClass();
Console.WriteLine(instance.TestInt); // 出力は 6 となります
}
}
6
コンストラクター内での正しい初期化方法
インスタンスコンストラクター内での初期化も許可されているため、以下のようにコンストラクター内で割り当てる方法もあります。
using System;
class MyClass
{
public readonly int TestInt; // 宣言時では初期化しない
public MyClass()
{
TestInt = 11; // コンストラクター内で初期化するので問題ありません
}
public static void Main()
{
MyClass instance = new MyClass();
Console.WriteLine(instance.TestInt); // 出力は 11 となります
}
}
11
修正後のコード例
以下は、ユーザーからの入力値などを利用して、readonly
フィールドをコンストラクター内で初期化する修正後の例です。
using System;
class MyClass
{
public readonly int TestInt;
public MyClass(int initValue)
{
// readonly フィールドは宣言時またはコンストラクター内でのみ代入可能
TestInt = initValue;
}
public static void Main()
{
MyClass instance = new MyClass(20);
Console.WriteLine($"TestInt: {instance.TestInt}"); // 出力は "TestInt: 20" となります
}
}
TestInt: 20
開発現場での対応事例
コードレビュー時の確認事項
コードレビュー時には、以下の点を確認することが推奨されます。
readonly
フィールドが宣言時またはコンストラクター内でのみ初期化されているかstatic readonly
フィールドが静的コンストラクターまたは宣言時に初期化されているか- 不要な再代入が行われていないか
既存コードのリファクタリング手法
既存コードのリファクタリングでは、以下の手法が有効です。
- 不適切な場所での
readonly
フィールドへの代入がないかを自動解析ツールでチェックする readonly
フィールドを活用して、初期化ロジックをコンストラクターに集約する- 静的フィールドの場合、必要に応じて静的コンストラクターを明示的に作成し、初期化処理を整理する
これらの対応により、CS0191 エラーの再発防止とコードの保守性向上が期待できます。
まとめ
この記事では、C# コンパイラエラー CS0191 の原因として、readonly フィールドへの不適切な代入が行われた際に発生するエラーについて解説しています。
インスタンスおよび静的フィールドの初期化制約、コンストラクターの正しい利用方法を具体例とともに示し、修正パターンを紹介しました。
コードレビューやリファクタリングの際の確認ポイントも取り上げ、エラーの再発防止に貢献できる情報を提供しています。