IndexOutOfRangeException / ArgumentOutOfRangeExceptionとは何ですか?どのように修正しますか?

197
Adriano Repetti 2014-01-06 14:19.

私はいくつかのコードを持っています、そしてそれが実行されるとき、それはIndexOutOfRangeException言って、をスローします、

インデックスが配列の範囲外だった。

これはどういう意味ですか、そして私はそれについて何ができますか?

使用するクラスによっては、 ArgumentOutOfRangeException

タイプ 'System.ArgumentOutOfRangeException'の例外がmscorlib.dllで発生しましたが、ユーザーコードで処理されませんでした。追加情報:インデックスが範囲外でした。負ではなく、コレクションのサイズ未満である必要があります。

4 answers

238
Adriano Repetti 2014-01-06 14:19.

それは何ですか?

この例外は、無効なインデックスを使用して、インデックスでコレクションアイテムにアクセスしようとしていることを意味します。コレクションの下限より低いか、含まれる要素の数以上の場合、インデックスは無効です。

投げられたとき

次のように宣言された配列があるとします。

byte[] array = new byte[4];

この配列には0から3までアクセスできますIndexOutOfRangeException。この範囲外の値は、スローされます。配列を作成してアクセスするときは、これを覚えておいてください。

配列の長さ
C#では、通常、配列は0ベースです。これは、最初の要素のインデックスが0で、最後の要素のインデックスLength - 1Length配列内のアイテムの総数)があるため、このコードは機能しないことを意味します。

array[array.Length] = 0;

さらに、多次元配列がある場合Array.Length、両方の次元に使用できない場合は、次を使用する必要があることに注意してArray.GetLength()ください。

int[,] data = new int[10, 5];
for (int i=0; i < data.GetLength(0); ++i) {
    for (int j=0; j < data.GetLength(1); ++j) {
        data[i, j] = 1;
    }
}

上界は包括的ではありません
次の例では、の生の2次元配列を作成しますColor。各項目はピクセルを表し、インデックスはから(0, 0)まで(imageWidth - 1, imageHeight - 1)です。

Color[,] pixels = new Color[imageWidth, imageHeight];
for (int x = 0; x <= imageWidth; ++x) {
    for (int y = 0; y <= imageHeight; ++y) {
        pixels[x, y] = backgroundColor;
    }
}

配列は0ベースであり、画像の最後(右下)のピクセルはpixels[imageWidth - 1, imageHeight - 1]次のとおりであるため、このコードは失敗します。

pixels[imageWidth, imageHeight] = Color.Black;

別のシナリオではArgumentOutOfRangeException、このコードを取得する場合があります(たとえばGetPixelBitmapクラスでメソッドを使用している場合)。

配列が大きくならない
配列は高速です。他のすべてのコレクションと比較して、線形検索で非常に高速です。これは、アイテムがメモリ内で連続しているため、メモリアドレスを計算できるためです(増分は単なる加算です)。ノードリストに従う必要はありません、簡単な計算です!これには制限があります。より多くの要素が必要な場合は、その配列を再割り当てする必要があります(古いアイテムを新しいブロックにコピーする必要がある場合、これには比較的長い時間がかかる可能性があります)。でサイズを変更しますArray.Resize<T>()。この例では、既存の配列に新しいエントリを追加します。

Array.Resize(ref array, array.Length + 1);

有効なインデックスはから0までであることを忘れないでくださいLength - 1。アイテムを割り当てようとすると、Length次のようになりますIndexOutOfRangeExceptionInsert他のコレクションのメソッドと同様の構文でアイテムが増えると思われる場合、この動作は混乱する可能性があります)。

カスタムの下限を持つ特別な配列配列の
最初の項目のインデックスは常に0です。カスタムの下限を使用して配列を作成できるため、これは常に当てはまるとは限りません。

var array = Array.CreateInstance(typeof(byte), new int[] { 4 }, new int[] { 1 });

この例では、配列インデックスは1から4まで有効です。もちろん、上限は変更できません。

間違った引数
(ユーザー入力または関数ユーザーから)検証されていない引数を使用して配列にアクセスすると、次のエラーが発生する可能性があります。

private static string[] RomanNumbers =
    new string[] { "I", "II", "III", "IV", "V" };

public static string Romanize(int number)
{
    return RomanNumbers[number];
}

予期しない結果
この例外は別の理由でもスローされる可能性があります。慣例により、多くの検索関数は-1を返します(nullableは.NET 2.0で導入されており、とにかく長年使用されているよく知られた規則でもあります)。 t何かを見つけます。文字列に匹敵するオブジェクトの配列があると想像してみましょう。あなたはこのコードを書くことを考えるかもしれません:

// Items comparable with a string
Console.WriteLine("First item equals to 'Debug' is '{0}'.",
    myArray[Array.IndexOf(myArray, "Debug")]);

// Arbitrary objects
Console.WriteLine("First item equals to 'Debug' is '{0}'.",
    myArray[Array.FindIndex(myArray, x => x.Type == "Debug")]);

-1を返し、配列アクセスがスローさmyArrayれるため、検索条件を満たすアイテムがない場合、これは失敗しArray.IndexOf()ます。

次の例は、特定の数値セットの出現を計算する単純な例です(最大数を認識し、インデックス0の項目が数値0を表し、インデックス1の項目が数値1を表す配列を返すなど)。

static int[] CountOccurences(int maximum, IEnumerable<int> numbers) {
    int[] result = new int[maximum + 1]; // Includes 0

    foreach (int number in numbers)
        ++result[number];

    return result;
}

もちろん、これはかなりひどい実装ですが、私が示したいのは、負の数と上記の数では失敗するということmaximumです。

それはどのように適用されList<T>ますか?

配列と同じ場合-有効なインデックスの範囲-0(Listのインデックスは常に0で始まります)からlist.Count-この範囲外の要素にアクセスすると、例外が発生します。

配列がを使用するのと同じ場合にList<T>スローArgumentOutOfRangeExceptionすることに注意してくださいIndexOutOfRangeException

配列とは異なり、List<T>空で開始します。したがって、作成したばかりのリストのアイテムにアクセスしようとすると、この例外が発生します。

var list = new List<int>();

一般的なケースは、リストにインデックスを作成することです(と同様Dictionary<int, T>)。例外が発生します。

list[0] = 42; // exception
list.Add(42); // correct

IDataReaderと列
次のコードを使用してデータベースからデータを読み取ろうとしていると想像してください。

using (var connection = CreateConnection()) {
    using (var command = connection.CreateCommand()) {
        command.CommandText = "SELECT MyColumn1, MyColumn2 FROM MyTable";

        using (var reader = command.ExecuteReader()) {
            while (reader.Read()) {
                ProcessData(reader.GetString(2)); // Throws!
            }
        }
    }
}

GetString()IndexOutOfRangeExceptionデータセットには2つの列しかないが、3番目の列から値を取得しようとしているためにスローされます(インデックスは常に0ベースです)。

この動作はほとんどのIDataReader実装(SqlDataReaderなどOleDbDataReader)で共有されていることに注意してください。

列名を取得して無効な列名を渡すインデクサー演算子のIDataReaderオーバーロードを使用した場合にも、同じ例外が発生する可能性があります。
たとえば、Column1という名前の列を取得したが、そのフィールドの値を次のように取得しようとしたとします。

 var data = dr["Colum1"];  // Missing the n in Column1.

これは、インデクサー演算子が、存在しないColum1フィールドのインデックスを取得しようとして実装されているために発生します。GetOrdinalメソッドは、内部ヘルパーコードが「Colum1」のインデックスとして-1を返すと、この例外をスローします。

その他
この例外がスローされる別の(文書化された)ケースがあります:でDataViewDataViewSortプロパティに提供されているデータ列名が無効である場合。

回避する方法

この例では、簡単にするために、配列は常に単次元で0ベースであると仮定します。あなたは、厳密な(またはライブラリを開発している)になりたい場合は、交換する必要があるかもしれない0GetLowerBound(0)して.LengthGetUpperBound(0)(あなたがタイプのパラメータを持っている場合はもちろんSystem.Arrayは、それが適用されませんT[])。この場合、上限は次のコードを含むことに注意してください。

for (int i=0; i < array.Length; ++i) { }

次のように書き直す必要があります。

for (int i=array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i) { }

これは許可されていないことに注意してください(スローされますInvalidCastException)。そのため、パラメータがT[]安全であれば、カスタムの下限配列について安全です。

void foo<T>(T[] array) { }

void test() {
    // This will throw InvalidCastException, cannot convert Int32[] to Int32[*]
    foo((int)Array.CreateInstance(typeof(int), new int[] { 1 }, new int[] { 1 }));
}

パラメータの検証
インデックスがパラメータに由来する場合は、常にそれらを検証する必要があります(適切なArgumentExceptionまたはをスローしますArgumentOutOfRangeException)。次の例では、間違ったパラメーターが原因IndexOutOfRangeExceptionである可能性があります。この関数のユーザーは、配列を渡しているためにこれを予期する可能性がありますが、必ずしもそれほど明白ではありません。パブリック関数のパラメーターを常に検証することをお勧めします。

static void SetRange<T>(T[] array, int from, int length, Func<i, T> function)
{
    if (from < 0 || from>= array.Length)
        throw new ArgumentOutOfRangeException("from");

    if (length < 0)
        throw new ArgumentOutOfRangeException("length");

    if (from + length > array.Length)
        throw new ArgumentException("...");

    for (int i=from; i < from + length; ++i)
        array[i] = function(i);
}

関数がプライベートの場合は、ifロジックをDebug.Assert()次のように置き換えるだけです。

Debug.Assert(from >= 0 && from < array.Length);

オブジェクト状態のチェック
配列インデックスがパラメータから直接取得されていない可能性があります。オブジェクト状態の一部である可能性があります。一般に、オブジェクトの状態を検証することは常に良い習慣です(それ自体で、必要に応じて関数パラメーターを使用して)。次の例のようにDebug.Assert()、を使用するか、適切な例外をスローするか(問題についてより説明的に)、またはそれを処理することができます。

class Table {
    public int SelectedIndex { get; set; }
    public Row[] Rows { get; set; }

    public Row SelectedRow {
        get {
            if (Rows == null)
                throw new InvalidOperationException("...");

            // No or wrong selection, here we just return null for
            // this case (it may be the reason we use this property
            // instead of direct access)
            if (SelectedIndex < 0 || SelectedIndex >= Rows.Length)
                return null;

            return Rows[SelectedIndex];
        }
}

戻り値の検証
前の例の1つでは、戻り値を直接使用しましたArray.IndexOf()。失敗する可能性があることがわかっている場合は、そのケースを処理することをお勧めします。

int index = myArray[Array.IndexOf(myArray, "Debug");
if (index != -1) { } else { }

デバッグ方法

私の意見では、このエラーに関するここSOに関する質問のほとんどは、簡単に回避できます。適切な質問を書くために費やす時間(小さな実用的な例と小さな説明を含む)は、コードをデバッグするために必要な時間よりもはるかに長くなる可能性があります。まず、小さなプログラムのデバッグに関するこのEric Lippertのブログ投稿を読んでください。ここでは彼の言葉を繰り返しませんが、絶対に読む必要があります

ソースコードがあり、スタックトレース付きの例外メッセージがあります。そこに行き、正しい行番号を選択すると、次のように表示されます。

array[index] = newValue;

エラーを見つけましたindex。どのように増加するかを確認してください。正しいですか?アレイがどのように割り当てられているかを確認し、どのようにindex増加するかと一貫性がありますか?あなたの仕様通りですか?これらすべての質問に「はい」と答えた場合は、StackOverflowで役立つ情報が見つかりますが、最初に自分で確認してください。あなたはあなた自身の時間を節約するでしょう!

良い出発点は、常にアサーションを使用し、入力を検証することです。コードコントラクトを使用することもできます。何かがうまくいかず、コードをざっと見て何が起こるか理解できない場合は、古くからの友人であるデバッガーに頼る必要があります。Visual Studio(またはお気に入りのIDE)内でデバッグ中のアプリケーションを実行するだけで、この例外をスローする行、関係する配列、使用しようとしているインデックスが正確にわかります。実際、99%の場合、数分で自分で解決できます。

これが本番環境で発生した場合は、犯罪のあるコードにアサーションを追加することをお勧めします。おそらく、自分では見ることができないものはコードに表示されません(ただし、いつでも賭けることができます)。

ストーリーのVB.NET側

C#の回答で述べたことはすべて、構文の違いが明らかなVB.NETでも有効ですが、VB.NETアレイを扱う際に考慮すべき重要な点があります。

VB.NETでは、配列は、配列の最大有効インデックス値を設定して宣言されます。配列に格納したい要素の数ではありません。

' declares an array with space for 5 integer 
' 4 is the maximum valid index starting from 0 to 4
Dim myArray(4) as Integer

したがって、このループは、IndexOutOfRangeExceptionを発生させることなく、配列を5つの整数で埋めます。

For i As Integer = 0 To 4
    myArray(i) = i
Next

VB.NETルール

この例外は、無効なインデックスを使用して、インデックスでコレクションアイテムにアクセスしようとしていることを意味します。コレクションの下限よりも低いか、よりも大きい場合、インデックスは無効です。含まれている要素の数に等しい。 配列宣言で定義されている最大許容インデックス

20
Lijo 2016-03-05 01:22.

インデックスの範囲外の例外とは何かについての簡単な説明:

1つの列車があり、そのコンパートメントはD1、D2、D3であると考えてください。一人の乗客が電車に乗り込み、D4のチケットを持っています。今何が起こるか。乗客は存在しないコンパートメントに入りたいので、明らかに問題が発生します。

同じシナリオ:配列リストなどにアクセスしようとすると、配列内の既存のインデックスにしかアクセスできません。array[0]array[1]存在しています。アクセスしようとするとarray[3]、実際には存在しないため、インデックスの範囲外の例外が発生します。

10
Snr 2017-12-07 20:48.

問題を簡単に理解するために、次のコードを記述したと想像してください。

static void Main(string[] args)
{
    string[] test = new string[3];
    test[0]= "hello1";
    test[1]= "hello2";
    test[2]= "hello3";

    for (int i = 0; i <= 3; i++)
    {
        Console.WriteLine(test[i].ToString());
    }
}

結果は次のようになります。

hello1
hello2
hello3

Unhandled Exception: System.IndexOutOfRangeException: Index was outside the bounds of the array.

配列のサイズは3(0、1、および2を示します)ですが、forループは4回(0、1、2、および3)ループします。
したがって、(3)を使用して境界外にアクセスしようとすると、例外がスローされます。

1
Ricibob 2019-03-01 22:51.

非常に長く完全に受け入れられた回答IndexOutOfRangeExceptionとは別に、他の多くの例外タイプと比較して重要なポイントがあります。それは次のとおりです。

多くの場合、コードの特定のポイントで制御するのが難しい複雑なプログラム状態があります。たとえば、DB接続がダウンして、入力のデータを取得できないなどです。この種の問題により、ある種の例外が発生することがよくあります。それが発生する場所にはその時点でそれを処理する方法がないため、より高いレベルにバブルアップする必要があります。

IndexOutOfRangeExceptionほとんどの場合、例外が発生している時点でチェックするのは非常に簡単であるという点で、一般的に異なります。一般に、この種の例外は、配列の実際の長さをチェックするだけで、発生している場所で問題を非常に簡単に処理できるコードによってスローされます。この例外をより高い位置で処理することによってこれを「修正」したくはありません-代わりに、最初のインスタンスでスローされないようにすることによって-これはほとんどの場合、配列の長さをチェックすることで簡単に行えます。

別の言い方をすれば、入力またはプログラムの状態を完全に制御できないために他の例外が発生する可能性がありますが、IndexOutOfRangeException多くの場合、単なるパイロット(プログラマー)エラーです。

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ジョー・バロウロー対ウェイド事件の転覆に対応するNFLは、言葉を言わないことで、腹立たしいが予測可能なPRの結果でした。

別の日、別のヒンジのないLIV記者会見

別の日、別のヒンジのないLIV記者会見

(lから)パット・ペレス、ブルックス・ケプカ、パトリック・リードサウジアラビアのLIVゴルフリーグのさらに別の信じられないほどの記者会見で、スポーツのファンはブルックス・ケプカからでたらめな吐き気と質問回避の驚異的なマスタークラスを受けました。パトリックリード、ブライソンデシャンボー、パットペレス、最近のPGAツアーの脱北者。

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

レッドダガーとマーベルさんがチームを組んでいます。

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

暗号業界最大の沈没船の1つであるスリーアローズキャピタルは、ついにその悲惨さから解放されています。火曜日に、不良債権ヘッジファンドは、債権者からの返済を要求する訴訟の高まりに応えて、バージンアイランド裁判所によって清算を命じられました彼らが3ACに行ったローン。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Suffragettes Indicam #3: Junho

Suffragettes Indicam #3: Junho

Mais um mês se findando — e metade do ano de 2022 já passou. Sabe o que isso significa? Não, não é hora de verificar se você está cumprindo com suas resoluções de Ano Novo.

多元宇宙—Junø

多元宇宙—Junø

チェーン間アカウントがJunoに登場します。異なるブロックチェーン間でスマートコントラクトの構成可能性と真の相互運用性を提供します。

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「​​ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。

メインネットガイド— Arbitrum Odyssey Week 2

メインネットガイド— Arbitrum Odyssey Week 2

最新のアップデートを受け取るために私たちに従ってください。ニュースレター:https://www。

Language