У меня есть некоторый код, и когда он выполняется, он бросает IndexOutOfRangeException
, говоря,
Индекс находился вне границ массива.
Что это значит, и что я могу с этим поделать?
В зависимости от используемых классов это также может быть ArgumentOutOfRangeException
Исключение типа «System.ArgumentOutOfRangeException» возникло в mscorlib.dll, но не было обработано в коде пользователя. Дополнительная информация: индекс находится вне диапазона. Должен быть неотрицательным и меньшим, чем размер коллекции.
c#
.net
indexoutofrangeexception
Адриано Репетти
источник
источник
Ответы:
Что это?
Это исключение означает, что вы пытаетесь получить доступ к элементу коллекции по индексу, используя недопустимый индекс. Индекс недопустим, если он ниже нижней границы коллекции или больше или равен количеству элементов, которые он содержит.
Когда это брошено
Данный массив объявлен как:
Вы можете получить доступ к этому массиву от 0 до 3, значения вне этого диапазона будут вызывать
IndexOutOfRangeException
выброс. Помните об этом, когда вы создаете и получаете доступ к массиву.Длина массива
В C # обычно массивы начинаются с 0. Это означает, что первый элемент имеет индекс 0, а последний элемент имеет индекс
Length - 1
(гдеLength
указано общее количество элементов в массиве), поэтому этот код не работает:Кроме того, обратите внимание, что если у вас есть многомерный массив, то вы не можете использовать
Array.Length
оба измерения, вы должны использоватьArray.GetLength()
:Верхняя граница не включена.
В следующем примере мы создаем необработанный двумерный массив
Color
. Каждый элемент представляет пиксель, индексы от(0, 0)
до(imageWidth - 1, imageHeight - 1)
.Этот код затем потерпит неудачу, потому что массив на основе 0 и последний (нижний правый) пиксель в изображении
pixels[imageWidth - 1, imageHeight - 1]
:В другом сценарии вы можете получить
ArgumentOutOfRangeException
этот код (например, если вы используетеGetPixel
метод вBitmap
классе).Массивы не растут
Массив быстр. Очень быстрый в линейном поиске по сравнению с любой другой коллекцией. Это связано с тем, что элементы находятся в памяти рядом, поэтому адрес памяти может быть вычислен (а приращение - всего лишь дополнение). Нет необходимости следить за списком узлов, простая математика! Вы платите это с ограничением: они не могут расти, если вам нужно больше элементов, вам нужно перераспределить этот массив (это может занять относительно много времени, если старые элементы должны быть скопированы в новый блок). Вы изменяете их размер
Array.Resize<T>()
, в этом примере добавляется новая запись в существующий массив:Не забывайте, что действительные индексы от
0
доLength - 1
. Если вы просто попытаетесь назначить элемент,Length
то получитеIndexOutOfRangeException
(это поведение может сбить вас с толку, если вы думаете, что он может увеличиться с синтаксисом, аналогичнымInsert
методу других коллекций).Специальные массивы с пользовательской нижней границей
Первый элемент в массивах всегда имеет индекс 0 . Это не всегда так, потому что вы можете создать массив с пользовательской нижней границей:
В этом примере индексы массива действительны от 1 до 4. Конечно, верхняя граница не может быть изменена.
Неправильные аргументы
Если вы обращаетесь к массиву с помощью непроверенных аргументов (из пользовательского ввода или из функции-пользователя), вы можете получить эту ошибку:
Неожиданные результаты
Это исключение может быть вызвано и по другой причине: по соглашению многие функции поиска будут возвращать -1 (nullables была введена в .NET 2.0 и в любом случае это также известное соглашение, используемое много лет назад), если они этого не сделали. ничего не могу найти. Давайте представим, что у вас есть массив объектов, сопоставимых со строкой. Вы можете написать этот код:
Это не удастся, если ни один из элементов не
myArray
будет удовлетворять условию поиска, потомуArray.IndexOf()
что вернет -1, а затем вызовет доступ к массиву.Следующий пример - наивный пример для вычисления вхождений данного набора чисел (зная максимальное число и возвращая массив, где элемент в индексе 0 представляет номер 0, элементы в индексе 1 представляют номер 1 и т. Д.):
Конечно, это довольно ужасная реализация, но я хочу показать, что она потерпит неудачу для отрицательных чисел и чисел выше
maximum
.Как это относится к
List<T>
?Те же случаи, что и в массиве - диапазон допустимых индексов - 0 (
List
индексы всегда начинаются с 0) дляlist.Count
доступа к элементам вне этого диапазона вызовет исключение.Обратите внимание, что
List<T>
выбрасываетArgumentOutOfRangeException
для тех же случаев, когда используют массивыIndexOutOfRangeException
.В отличие от массивов,
List<T>
начинается пусто - поэтому попытки доступа к элементам только что созданного списка приводят к этому исключению.Распространенный случай - заполнение списка индексацией (аналогично
Dictionary<int, T>
) приведет к исключению:IDataReader and Columns
Представьте, что вы пытаетесь прочитать данные из базы данных с помощью следующего кода:
GetString()
будет выброшено,IndexOutOfRangeException
потому что у вашего набора данных есть только два столбца, но вы пытаетесь получить значение от третьего (индексы всегда основаны на 0).Обратите внимание , что такое поведение является общей для большинства
IDataReader
реализаций (SqlDataReader
,OleDbDataReader
и так далее).Вы можете получить то же исключение и в том случае, если вы используете перегрузку IDataReader оператора индексатора, который принимает имя столбца и передает неверное имя столбца.
Предположим, например, что вы получили столбец с именем Column1, но затем вы пытаетесь получить значение этого поля с помощью
Это происходит потому, что оператор индексатора реализован, пытаясь получить индекс поля Colum1, которое не существует. Метод GetOrdinal выдает это исключение, когда его внутренний вспомогательный код возвращает -1 в качестве индекса «Colum1».
Другое
Существует еще один (задокументированный) случай, когда выбрасывается это исключение: если
DataView
имя столбца данных, передаваемое вDataViewSort
свойство, недопустимо.Как избежать
В этом примере позвольте мне для простоты предположить, что массивы всегда являются одномерными и основаны на 0. Если вы хотите быть строгим (или разрабатываете библиотеку), вам может потребоваться заменить
0
наGetLowerBound(0)
и.Length
наGetUpperBound(0)
(конечно, если у вас есть параметры типаSystem.Arra
y, он не применяетсяT[]
). Обратите внимание, что в этом случае верхняя граница включает в себя этот код:Должен быть переписан так:
Пожалуйста, обратите внимание, что это недопустимо (оно выдает
InvalidCastException
), поэтому, если ваши параметрыT[]
безопасны для пользовательских массивов нижней границы:Проверка параметров
Если индекс происходит от параметра, вы всегда должны проверять его (выбрасывая соответствующий
ArgumentException
илиArgumentOutOfRangeException
). В следующем примере могут возникнуть неправильные параметрыIndexOutOfRangeException
, пользователи этой функции могут ожидать этого, потому что они передают массив, но это не всегда так очевидно. Я бы предложил всегда проверять параметры для публичных функций:Если функция закрыта, вы можете просто заменить
if
логику наDebug.Assert()
:Проверка состояния объекта
Индекс массива может не исходить непосредственно из параметра. Это может быть частью состояния объекта. В целом, всегда полезно проверять состояние объекта (само по себе и с параметрами функции, если необходимо). Вы можете использовать
Debug.Assert()
, выбросить правильное исключение (более подробно о проблеме) или обработать, как в этом примере:Проверка возвращаемых значений
В одном из предыдущих примеров мы напрямую использовали
Array.IndexOf()
возвращаемое значение. Если мы знаем, что это может потерпеть неудачу, тогда лучше разобраться с этим случаем:Как отлаживать
На мой взгляд, большинство вопросов здесь, на SO, об этой ошибке можно просто избежать. Время, которое вы тратите на написание правильного вопроса (с небольшим рабочим примером и небольшим объяснением), может легко превысить время, необходимое для отладки кода. Прежде всего, прочитайте этот пост Эрика Липперта в блоге об отладке небольших программ , я не буду повторять его слова здесь, но это абсолютно необходимо прочитать .
У вас есть исходный код, у вас есть сообщение об исключении с трассировкой стека. Идите туда, выберите правильный номер строки, и вы увидите:
Вы нашли свою ошибку, проверьте, насколько
index
увеличивается. Это правильно? Проверь, как распределяется массив, согласуется с тем, какindex
увеличивается? Это правильно в соответствии с вашими требованиями? Если вы ответите « да» на все эти вопросы, то вы найдете здесь полезную помощь в StackOverflow, но сначала проверьте это самостоятельно. Вы сэкономите свое время!Хорошей отправной точкой является всегда использовать утверждения и проверять входные данные. Вы можете даже хотеть использовать кодовые контракты. Когда что-то пошло не так, и вы не можете понять, что происходит, быстро взглянув на свой код, вам придется прибегнуть к помощи старого друга: отладчика . Просто запустите ваше приложение в режиме отладки в Visual Studio (или вашей любимой IDE), и вы увидите, какая именно строка выдает это исключение, какой массив задействован и какой индекс вы пытаетесь использовать. Действительно, в 99% случаев вы решите это самостоятельно за несколько минут.
Если это происходит в производственной среде, то вам лучше добавить утверждения в инкриминируемый код, возможно, мы не увидим в вашем коде то, что вы не можете увидеть самостоятельно (но вы всегда можете сделать ставку).
VB.NET сторона истории
Все, что мы сказали в ответе на C #, действительно для VB.NET с очевидными синтаксическими различиями, но есть важный момент, который необходимо учитывать при работе с массивами VB.NET.
В VB.NET объявляются массивы, задающие максимальное допустимое значение индекса для массива. Это не количество элементов, которые мы хотим сохранить в массиве.
Таким образом, этот цикл будет заполнять массив 5 целыми числами, не вызывая никакого IndexOutOfRangeException
Правило VB.NET
Это исключение означает, что вы пытаетесь получить доступ к элементу коллекции по индексу, используя недопустимый индекс. Индекс недопустим, если он ниже нижней границы коллекции или больше
равно количеству элементов, которые оно содержит.максимально допустимый индекс, определенный в объявлении массиваисточник
Простое объяснение того, что такое исключение Index вне привязки:
Подумайте только, что там есть один поезд, его купе D1, D2, D3. Один пассажир пришел, чтобы войти в поезд, и у него есть билет на D4. теперь что будет. пассажир хочет войти в отсек, который не существует, поэтому очевидно, что проблема возникнет.
Тот же сценарий: всякий раз, когда мы пытаемся получить доступ к списку массивов и т. Д., Мы можем получить доступ только к существующим индексам в массиве.
array[0]
иarray[1]
существуют. Если мы попытаемся получить доступarray[3]
, его там на самом деле нет, поэтому возникнет исключение из индекса.источник
Чтобы легко понять проблему, представьте, что мы написали этот код:
Результат будет:
Размер массива равен 3 (индексы 0, 1 и 2), но цикл for повторяется 4 раза (0, 1, 2 и 3).
Поэтому, когда он пытается получить доступ за пределами (3), он генерирует исключение.
источник
Помимо очень длинного полного принятого ответа, есть важный момент, который нужно
IndexOutOfRangeException
сравнить со многими другими типами исключений, а именно:Часто существует сложное состояние программы, которое может быть трудно контролировать в определенной точке кода, например, соединение с БД прерывается, поэтому данные для входа не могут быть извлечены и т. Д. ... Этот тип проблемы часто приводит к исключению некоторого вида, которое должен подняться на более высокий уровень, потому что там, где это происходит, нет никакого способа справиться с этим на этом этапе.
IndexOutOfRangeException
обычно отличается тем, что в большинстве случаев проверять в точке, где возникает исключение, довольно тривиально. Обычно такого рода исключения вызываются некоторым кодом, который может очень легко справиться с проблемой в том месте, где она возникает, просто проверяя фактическую длину массива. Вы не хотите «исправлять» это, обрабатывая это исключение выше - но вместо этого гарантируя, что оно не будет выброшено в первый раз - что в большинстве случаев легко сделать, проверив длину массива.Другой способ выразить это заключается в том, что другие исключения могут возникать из-за подлинного отсутствия контроля над вводом или состоянием программы, НО
IndexOutOfRangeException
чаще всего это просто ошибка пилота (программиста).источник