Code Fix

上級

A readonly field cannot be assigned to の原因と直し方

readonly修飾子を付けたフィールドを、コンストラクタや初期化子以外の場所で書き換えようとすると出るコンパイルエラーです。

エラーメッセージの読み方

Program.cs(5,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
Program.cs
ファイル名
5
行番号
9
列番号 — この位置でコンパイラが解析に失敗しました
CS0191
エラーコード — 検索するとMicrosoftの解説ページが見つかります
A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)
内容 — 期待していたもの、または受け付けられなかったもの

このエラーが出る典型パターン

パターン1

 1  class Config {
 2      public readonly int MaxUsers = 100;
 3      public int CurrentUsers = 0;
 4      public void Reset() {
 5          MaxUsers     = 50;
                  ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          Config c = new Config();
11          c.Reset();
12          System.Console.WriteLine(c.CurrentUsers);
13      }
14  }
Program.cs(5,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)

readonlyなフィールドはコンストラクタ以外から代入できません。書き換えたい値は普通のフィールドにする必要があります。

直し方: MaxUsers を CurrentUsers にします。

この問題を解いてみる →

広告
広告スロット(未設定)

パターン2

 1  class Product {
 2      public readonly string Id = "P-1";
 3      public int Stock = 0;
 4      public void Restock() {
 5          Id    = 20;
              ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          Product p = new Product();
11          p.Restock();
12          System.Console.WriteLine(p.Stock);
13      }
14  }
Program.cs(5,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)

Idは商品を識別するための値なので変更させたくありません。readonlyにすることで代入をコンパイル時に防げます。

直し方: Id を Stock にします。

この問題を解いてみる →

パターン3

 1  class GameConfig {
 2      public readonly int MaxLevel = 99;
 3      public int CurrentLevel = 1;
 4      public void LevelUp() {
 5          MaxLevel     = CurrentLevel + 1;
                  ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          GameConfig g = new GameConfig();
11          g.LevelUp();
12          System.Console.WriteLine(g.CurrentLevel);
13      }
14  }
Program.cs(5,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)

上限値のような変わってほしくない値をreadonlyにしておくと、誤って書き換えるコードをコンパイル時に検出できます。

直し方: MaxLevel を CurrentLevel にします。

この問題を解いてみる →

パターン4

 1  class Account {
 2      public readonly string Owner = "Alice";
 3      public int Balance = 0;
 4      public void Deposit() {
 5          Owner   = 100;
               ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          Account acc = new Account();
11          acc.Deposit();
12          System.Console.WriteLine(acc.Balance);
13      }
14  }
Program.cs(5,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)

Ownerはreadonlyなので、コンストラクタの外にあるDepositメソッドから代入することはできません。

直し方: Owner を Balance にします。

この問題を解いてみる →

パターン5

 1  class Ticket {
 2      public readonly int EventId = 7;
 3      public int Seats = 0;
 4      public void Book() {
 5          EventId = 4;
               ^
 6      }
 7  }
 8  class Program {
 9      static void Main(string[] args) {
10          Ticket t = new Ticket();
11          t.Book();
12          System.Console.WriteLine(t.Seats);
13      }
14  }
Program.cs(5,9): error CS0191: A readonly field cannot be assigned to (except in a constructor or init-only setter of the type in which the field is defined or a variable initializer)

EventIdのように識別のための値をreadonlyにしておくと、誤って上書きするコードをコンパイル時に検出できます。

直し方: EventId を Seats にします。

この問題を解いてみる →

よくある誤解

readonlyはコンストラクタの中でも常に書けるわけではなく、そのフィールドを定義した型のコンストラクタからしか書けません。継承先のコンストラクタからも書けない点に注意が必要です。

実務での勘所

readonlyとconstは似ていますが別物です。constはコンパイル時に値が確定していなければならず、暗黙的にstaticになります(インスタンスごとに違う値を持てません)。readonlyはコンストラクタの実行時に(引数などを使って)動的に値を決めることができ、インスタンスごとに異なる値を持てます。「宣言と同時に固定値を書くならconst、インスタンスごとに1回だけ計算して以後変えないならreadonly」という使い分けが実務の目安です。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)