Code Fix

中級

ArgumentOutOfRangeException の原因と直し方

List<T>のインデクサに範囲外の値を渡すと発生します。配列のIndexOutOfRangeExceptionとは異なる例外クラスです。

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

Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
System
名前空間 — System なら標準の基本例外です
ArgumentOutOfRangeException
例外クラス — 何が起きたか。ここを検索するのが最短です
Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index')
詳細メッセージ — どの値が問題だったか
at Program.Main(String[] args) in Program.cs:line 4
発生箇所 — スタックトレースの先頭行

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

パターン1

 1  class Program {
 2      static void Main(string[] args) {
 3          var nums = new System.Collections.Generic.List<int> { 1, 2, 3 };
 4          System.Console.WriteLine(nums[5 ]);
                                           ^
 5      }
 6  }
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index') at Program.Main(String[] args) in Program.cs:line 4

List<T>のインデクサは配列と違い、範囲外を指定するとArgumentOutOfRangeExceptionを投げます(配列のIndexOutOfRangeExceptionとは型が違います)。

直し方: 5 を 1 にします。

この問題を解いてみる →

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

パターン2

 1  class Program {
 2      static void Main(string[] args) {
 3          var nums = new System.Collections.Generic.List<int> { 1, 2, 3 };
 4          int idx = -1;
                       ^
 5          System.Console.WriteLine(nums[idx]);
 6      }
 7  }
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index') at Program.Main(String[] args) in Program.cs:line 5

負のインデックスも同様にArgumentOutOfRangeExceptionになります。

直し方: -1 を 0 にします。

この問題を解いてみる →

パターン3

 1  class Program {
 2      static void Main(string[] args) {
 3          var names = new System.Collections.Generic.List<string> { "a", "b" };
 4          System.Console.WriteLine(names[2 ]);
                                            ^
 5      }
 6  }
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index') at Program.Main(String[] args) in Program.cs:line 4

要素数2のリストで有効なインデックスは0と1だけです。Countと最大インデックスを混同しないようにします。

直し方: 2 を 1 にします。

この問題を解いてみる →

パターン4

 1  class Program {
 2      static void Main(string[] args) {
 3          var vals = new System.Collections.Generic.List<int> { 4, 8, 15 };
 4          System.Console.WriteLine(vals[9 ]);
                                           ^
 5      }
 6  }
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index') at Program.Main(String[] args) in Program.cs:line 4

List<T>のインデクサも配列と同様、範囲外を指定すると例外になります。

直し方: 9 を 2 にします。

この問題を解いてみる →

パターン5

 1  class Program {
 2      static void Main(string[] args) {
 3          var items = new System.Collections.Generic.List<string> { "x", "y", "z" };
 4          int idx = 3 ;
                       ^
 5          System.Console.WriteLine(items[idx]);
 6      }
 7  }
Unhandled exception. System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection. (Parameter 'index') at Program.Main(String[] args) in Program.cs:line 5

要素数3のリストで有効なインデックスは0〜2までです。3は1つ超えています。

直し方: 3 を 0 にします。

この問題を解いてみる →

よくある誤解

配列とList<T>は似ていますが、範囲外アクセス時に投げる例外の型が違います。catchするときはこの違いに注意が必要です。

実務での勘所

配列とList<T>で例外の型が違うのは、実装の層が違うためです。配列は.NET 1.0の時代からCLRに直接組み込まれたプリミティブな存在で、専用のIndexOutOfRangeExceptionを持っています。List<T>は.NET 2.0でジェネリクスとともに追加された、C#自身で書かれた通常のクラスで、範囲チェックの実装には「引数の値が許容範囲外である」という、BCL全体で汎用的に使われるArgumentOutOfRangeExceptionを利用しています。catchするコードを書くときは、対象がT[]なのかList<T>なのかで例外の型を正しく使い分ける必要があります。

演習をはじめる

関連するエラー

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