什么是IndexOutOfRangeException,如何解决呢? [英] What is IndexOutOfRangeException and how do I fix it?

查看:9774
本文介绍了什么是IndexOutOfRangeException,如何解决呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些code和在执行时,它抛出一个 IndexOutOfRangeException ,说,索引数组的范围以外。

I have some code and when it executes, it throws a IndexOutOfRangeException, saying, "Index was outside the bounds of the array.".

这是什么意思,和我能做些什么呢?

What does this mean, and what can I do about it?


当然,这不是一个真正的问题;我发现有很多问题,在这里等都是与此相关的错误让一个一般性的指导(像这样的<一个href="http://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it">NullReferenceException)可能是有用的,答案是一个社区的wiki,有提示或常见的场景编辑会更受欢迎。


Of course this is not a real question; I found many questions here on SO are related to this error so a general guidance (like this one for NullReferenceException) may be useful. Answer is a community wiki, edits with tips or common scenarios will be more than welcome.

推荐答案

这异常意味着你试图(直接或间接)访问(读取或写入)使用无效的索引数组。指数是无效的,当它比数组的下限或大于或等于其包含的元素数量降低。

What Is It?

This exception means that you're trying (directly or indirectly) accessing (for reading or for writing) an array using an invalid index. Index is invalid when it's lower than array's lower bound or greater or equal than number of elements it contains.

由于声明数组:

byte[] array = new byte[4];

您可以访问该数组从0到3,超出此范围的值会导致 IndexOutOfRangeException 被抛出。记住这一点,当你创建和访问数组。

You can access this array from 0 to 3, values outside this range will cause IndexOutOfRangeException to be thrown. Remember this when you create and access an array.

数组的长度
在C#中,通常情况下,数组是基于0的。这意味着第一个元​​素的索引是0,最后一个元素的索引长度 - 1 (其中长度是项目总数在数组),所以这个code不工作:

Array Length
In C#, usually, arrays are 0-based. It means that first element has index 0 and last element has index Length - 1 (where Length is total number of items in the array) so this code doesn't work:

array[array.Length] = 0;

另外请注意,如果你有一个多维数组,那么你不能使用 Array.Length 这两个维度,你必须使用阵列.GetLength()

Moreover please note that if you have a multidimensional array then you can't use Array.Length for both dimension, you have to use 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;
    }
}

上限并不包括
在下面的例子中,我们创建颜色原始二维数组。再$ P $每个项目psents像素,指数从(0,0)(ImageWidth等 - 1,imageHeight - 1)

Upper Bound Is Not Inclusive
In the following example we create a raw bidimensional array of Color. Each item represents a pixel, indices are from (0, 0) to (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;
    }
}

那么这code会因为阵列0和基于图像中最后的(右下)像素是失败像素[ImageWidth等 - 1,imageHeight - 1]

pixels[imageWidth, imageHeight] = Color.Black;

在另一种情况下,你可能会得到 ArgumentOutOfRangeException 此code(例如,如果你使用 GetPixel 方法上的位图类)。

In another scenario you may get ArgumentOutOfRangeException for this code (for example if you're using GetPixel method on a Bitmap class).

阵列不长
数组快。非常快,线性搜索比所有其他收藏。这是因为各条目是相连的存储器,以便存储地址可以计算(和增量只是一个补充)。无需遵循节点列表,简单的数学!你支付这笔用一个限制:它们不能生长,如果你需要更多的元素,你需要重新分配该数组(这可能是广​​阔的,如果旧项目必须复制到新的块)。你调整它们与 Array.Resize&LT; T&GT;(),这个例子中增加了一个新的项目,以现有的数组:

Arrays Do Not Grow
An array is fast. Very fast in linear search compared to every other collection. It is because items are contiguous in memory so memory address can be calculated (and increment is just an addition). No need to follow a node list, simple math! You pay this with a limitation: they can't grow, if you need more elements you need to reallocate that array (this may be expansive if old items must be copied to a new block). You resize them with Array.Resize<T>(), this example adds a new entry to an existing array:

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

不要忘了有效的指标是从 0 长度 - 1 。如果你只是一味的在分配项目长度你会得到 IndexOutOfRangeException (如果你觉得这个行为可能会迷惑你它们可能会增加与类似于其他收藏插入法)语法。

Don't forget that valid indices are from 0 to Length - 1. If you simply try to assign an item at Length you'll get IndexOutOfRangeException (this behavior may confuse you if you think they may increase with a syntax similar to Insert method of other collections).

特别的阵列,定制下限
在数组中第一个项目的总指数0 的。这并不总是正确的,因为你可以创建一个自定义的下界的数组:

Special Arrays With Custom Lower Bound
First item in arrays has always index 0. This is not always true because you can create an array with a custom lower bound:

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

在这个例子中数组的索引是有效的,从1到4当然上限不能改变。

In that example array indices are valid from 1 to 4. Of course upper bound cannot be changed.

错误参数
如果您使用的是未经验证的参数(来自用户输入或功能的用户)访问数组,你可能会得到这个错误:

Wrong Arguments
If you access an array using unvalidated arguments (from user input or from function user) you may get this error:

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

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

意外的结果
这可能会引发异常的另一个原因也:按照惯例许多的搜索功能的将返回-1(nullables已经引入了.NET 2.0,反正它也从多年使用的一个众所周知的约定)如果他们没有发现任何东西。让我们想象一下,你有对象使用一个字符串比较的数组。你可能会认为写这篇code:

Unexpected Results
This exception may be thrown for another reason too: by convention many search functions will return -1 (nullables has been introduced with .NET 2.0 and anyway it's also a well-known convention in use from many years) if they didn't find anything. Let's imagine you have an array of objects comparable with a string. You may think to write this code:

// 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")]);

这将失败,如果在 myArray的没有产品将满足搜索条件,因为 Array.IndexOf()返回 - 1,然后数组访问将抛出。

This will fail if no items in myArray will satisfy search condition because Array.IndexOf() will return -1 and then array access will throw.

接下来的例子是一个天真的例子来计算出现一组给定数字的(知道最大数量,并返回一个数组,其中索引0重新presents数0项,在索引1再presents号1项等):

Next example is a naive example to calculate occurrences of a given set of numbers (knowing maximum number and returning an array where item at index 0 represents number 0, items at index 1 represents number 1 and so on):

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;
}

当然,这是一个pretty的可怕的实现,但我想表明的是,它会失败负数和数字高于最高

如何适用<一个href="http://msdn.microsoft.com/en-us/library/6sh2ey19%28v=vs.110%29.aspx"><$c$c>List<T>?

同一案件阵列 - 一系列有效指标 - 0(列表的索引总是从0开始),以 list.Count - 访问此范围之外的元素将引起异常

Same cases as array - range of valid indexes - 0 (List's indexes always start with 0) to list.Count - accessing elements outside of this range will cause the exception.

与数组不同,名单,其中,T&GT; 启动空的 - 所以试图访问刚刚创建的列表项导致该异常

Unlike arrays, List<T> starts empty - so trying to access items of just created list lead to this exception.

var list = new List<int>();

常见的情况是,以使用索引列表(类似于词典&LT; INT,T&GT; )将导致异常:

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

的IDataReader和列
想象一下,你想从这个code数据库中读取数据:

IDataReader and Columns
Imagine you're trying to read data from a database with this code:

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 因为你的数据集只有两列,但你要获得第三一个值(指数总是的从0开始)。

GetString() will throw IndexOutOfRangeException because you're dataset has only two columns but you're trying to get a value from 3rd one (indices are always 0-based).

请注意,此行为与大多数的IDataReader 实现( SqlDataReader的 OleDbDataReader共享等)。

Please note that this behavior is shared with most IDataReader implementations (SqlDataReader, OleDbDataReader and so on).

其他
有此异常时抛出另一个(记录)的情况下:如果在数据视图,数据列名被提供给 DataViewSort 属性是无效的。

Others
There is another (documented) case when this exception is thrown: if, in DataView, data column name being supplied to the DataViewSort property is not valid.

在本实施例,让我假定,为简单起见,该阵列是总是单维和0为主。如果你想成为严格的(或需要的资料开发库),你可能需要更换 0 GetLowerBound(0) .Length GetUpperBound(0)(当然,如果你有参数类型为 System.Arra Y,它并不适用于 T [] )。请注意,在这种情况下,上界是包容然后这个code:

In this examples let me assume, for simplicity, that arrays are always monodimensional and 0-based. If you want to be strict (or your're developing a library) you may need to replace 0 with GetLowerBound(0) and .Length with GetUpperBound(0) (of course if you have parameters of type System.Array, it doesn't apply for T[]). Please note that in this case upper bound is inclusive then this code:

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

要写成这样:

Should be rewritten like this:

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

请注意,这是不允许的(它会抛出 InvalidCastException的),这就是为什么如果你的参数是 T [] 你是安全的有关自定义下界数组:

Please note that this is not allowed (it'll throw InvalidCastException), that's why if your parameters are T[] you're safe about custom lower bound arrays:

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 ,这个功能的用户可能会想到这一点,因为他们传递一个数组,但它并不总是那么明显。我建议要始终验证参数的公共职能:

Validate Parameters
If index comes from a parameter you should always validate them (throwing appropriate ArgumentException or ArgumentOutOfRangeException). In next example wrong parameters may cause IndexOutOfRangeException, users of this function may expect this because they're passing an array but it's not always so obvious. I'd suggest to always validate parameters for public functions:

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);
}

如果函数是私有的,你可以简单地替换如果逻辑与 Debug.Assert的()

If function is private you may simply replace if logic with Debug.Assert():

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

检查对象的状态
从参数数组索引可能不会直接来了。这可能是对象状态的一部分。在一般情况始终是一个很好的做法,以验证对象的状态(通过自身和功能参数,如果需要的话)。您可以使用 Debug.Assert的(),抛出一个适当的异常(更多的描述有关该问题),或者搞定就像这个例子:

Check Object State
Array index may not come directly from a parameter. It may be part of object state. In general is always a good practice to validate object state (by itself and with function parameters, if needed). You can use Debug.Assert(), throw a proper exception (more descriptive about the problem) or handle that like in this example:

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];
        }
}

验证返回值:
在previous一个例子,我们直接使用 Array.IndexOf()返回值。如果我们知道它可能会失败,那么它是更好地处理这种情况:

Validate Return Values
In one of previous examples we directly used Array.IndexOf() return value. If we know it may fail then it's better to handle that case:

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

如何调试

在大多数问题我看来,这里SO,这个错误可以简单地避免。你的时间花在写一个正确的问题(一个小的工作示例和一个小的解释)可以很容易地不是时间多,你需要调试你的code。首先阅读本埃里克利珀的博客文章了解的href="http://ericlippert.com/2014/03/05/how-to-debug-small-programs/">调试,我就不再重复他的话在这里,但它是一个绝对的必须阅读的。

How to Debug

In my opinion most of questions, here on SO, about this error can be simply avoided. Time you spend to write a proper question (with a small working example and a small explanation) could easily much more than time you'll need to debug your code. First of all read this Eric Lippert's blog post about debugging of small programs, I won't repeat his words here but it's absolutely a must read.

您有源$ C ​​$ C,你有堆栈跟踪异常消息。去那里,挑选合适的行号,你会看到:

You have source code, you have exception message with stack trace. Go there, pick right line number and you'll see:

array[index] = newValue;

您发现您的错误,检查有首页增大。这样对吗?检查数组如何分配,是一致的如何首页增加?是不是根据你的specifiation?如果你回答的的所有这些问题,那么你会在这里的StackOverflow找到很好的帮助,但请为先检查自己。你可以节省自己的时间!

You found your error, check how index increases. Is it right? Check how array is allocated, is coherent with how index increases? Is it right according your specifiation? If you answer yes to all these questions then you'll find good help here on StackOverflow but please first check for that by yourself. You'll save your own time!

一个很好的起点是始终使用断言和验证的投入。你甚至可以用code合同。如果出了问题,你不能找出一个快速浏览一下你的code会发生什么,那么你不得不求助于一个老朋友:调试。只要运行在调试在Visual Studio中(或者您喜欢的IDE)您的应用程序,你会看到到底是哪个行抛出此异常,这阵参与和你想使用哪个索引。说真的,99%的时候,你会在几分钟内解决它自己。

A good start point is to always use assertions and to validate inputs. You may even want to use code contracts. When something went wrong and you can't figure out what happens with a quick look at your code then you have to resort an old friend: debugger. Just run your application in debug inside Visual Studio (or your favorite IDE), you'll see exactly which line throws this exception, which array is involved and which index you're trying to use. Really, 99% of times you'll solve it by yourself in few minutes.

如果这发生在生产那么你最好在入罪code添加断言,也许我们不会在code见你无法自己看到什么(但你总是可以打赌)

If this happens in production then you'd better to add assertions in incriminated code, probably we won't see in your code what you can't see by yourself (but you can always bet).

这篇关于什么是IndexOutOfRangeException,如何解决呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆