Tengo un código y cuando se ejecuta, arroja un IndexOutOfRangeException
, diciendo:
El índice esta fuera de los límites de la matriz.
¿Qué significa esto y qué puedo hacer al respecto?
Dependiendo de las clases utilizadas, también puede ser ArgumentOutOfRangeException
Se produjo una excepción del tipo 'System.ArgumentOutOfRangeException' en mscorlib.dll pero no se manejó en el código de usuario Información adicional: El índice estaba fuera de rango. Debe ser no negativo y menor que el tamaño de la colección.
c#
.net
indexoutofrangeexception
Adriano Repetti
fuente
fuente
Respuestas:
¿Qué es?
Esta excepción significa que está intentando acceder a un elemento de colección por índice, utilizando un índice no válido. Un índice no es válido cuando es inferior al límite inferior de la colección o mayor o igual que el número de elementos que contiene.
Cuando es lanzado
Dado un conjunto declarado como:
Puede acceder a esta matriz de 0 a 3, los valores fuera de este rango harán
IndexOutOfRangeException
que se arrojen. Recuerde esto cuando cree y acceda a una matriz.Longitud de matriz
En C #, generalmente, las matrices están basadas en 0. Significa que el primer elemento tiene índice 0 y el último elemento tiene índice
Length - 1
(dondeLength
es el número total de elementos en la matriz), por lo que este código no funciona:Además, tenga en cuenta que si tiene una matriz multidimensional, entonces no puede usar
Array.Length
para ambas dimensiones, debe usarArray.GetLength()
:Upper Bound no es inclusivo
En el siguiente ejemplo creamos una matriz bidimensional cruda de
Color
. Cada elemento representa un píxel, los índices son de(0, 0)
a(imageWidth - 1, imageHeight - 1)
.Este código fallará porque la matriz está basada en 0 y el último píxel (inferior derecho) de la imagen es
pixels[imageWidth - 1, imageHeight - 1]
:En otro escenario, puede obtener
ArgumentOutOfRangeException
este código (por ejemplo, si está utilizandoGetPixel
método en unaBitmap
clase).Las matrices no crecen
Una matriz es rápida. Muy rápido en búsqueda lineal en comparación con cualquier otra colección. Esto se debe a que los elementos son contiguos en la memoria, por lo que se puede calcular la dirección de la memoria (y el incremento es solo una adición). No es necesario seguir una lista de nodos, ¡simple matemática! Paga esto con una limitación: no pueden crecer, si necesita más elementos necesita reasignar esa matriz (esto puede llevar un tiempo relativamente largo si los elementos antiguos deben copiarse en un nuevo bloque). Los redimensiona con
Array.Resize<T>()
, este ejemplo agrega una nueva entrada a una matriz existente:No olvide que los índices válidos son de
0
aLength - 1
. Si simplemente intentas asignar un elemento aLength
, obtendrásIndexOutOfRangeException
(este comportamiento puede confundirlo si cree que puede aumentar con una sintaxis similar alInsert
método de otras colecciones).Arreglos especiales con límite inferior personalizado El
primer elemento en los arreglos siempre tiene un índice 0 . Esto no siempre es cierto porque puede crear una matriz con un límite inferior personalizado:
En ese ejemplo, los índices de matriz son válidos de 1 a 4. Por supuesto, el límite superior no se puede cambiar.
Argumentos incorrectos
Si accede a una matriz utilizando argumentos no validados (de la entrada del usuario o del usuario de la función), puede obtener este error:
Resultados inesperados
Esta excepción también puede producirse por otra razón: por convención, muchas funciones de búsqueda devolverán -1 (se han introducido valores anulables con .NET 2.0 y, de todos modos, también es una convención bien conocida en uso desde hace muchos años) si no No encuentro nada. Imaginemos que tiene una matriz de objetos comparables con una cadena. Puede pensar en escribir este código:
Esto fallará si ningún elemento en
myArray
satisface la condición de búsqueda porqueArray.IndexOf()
devolverá -1 y luego se lanzará el acceso a la matriz.El siguiente ejemplo es un ejemplo ingenuo para calcular las ocurrencias de un conjunto de números dado (conocer el número máximo y devolver una matriz donde el elemento en el índice 0 representa el número 0, los elementos en el índice 1 representan el número 1 y así sucesivamente):
Por supuesto, es una implementación bastante terrible, pero lo que quiero mostrar es que fallará para los números negativos y los números anteriores
maximum
.Cómo se aplica a
List<T>
?Los mismos casos que la matriz - rango de índices válidos - 0 (
List
los índices siempre comienzan con 0) alist.Count
- acceder a elementos fuera de este rango causará la excepción.Tenga en cuenta que
List<T>
arrojaArgumentOutOfRangeException
para los mismos casos donde las matrices usanIndexOutOfRangeException
.A diferencia de las matrices,
List<T>
comienza vacío, por lo que intentar acceder a los elementos de la lista recién creada conduce a esta excepción.El caso común es llenar la lista con indexación (similar a
Dictionary<int, T>
) causará una excepción:IDataReader y columnas
Imagine que está intentando leer datos de una base de datos con este código:
GetString()
arrojaráIndexOutOfRangeException
porque su conjunto de datos tiene solo dos columnas, pero está tratando de obtener un valor de la tercera (los índices son siempre basados en 0).Tenga en cuenta que este comportamiento se comparte con la mayoría de las
IDataReader
implementaciones (SqlDataReader
,OleDbDataReader
y así sucesivamente).También puede obtener la misma excepción si usa la sobrecarga IDataReader del operador del indexador que toma un nombre de columna y pasa un nombre de columna no válido.
Supongamos, por ejemplo, que ha recuperado una columna llamada Columna1 pero luego intenta recuperar el valor de ese campo con
Esto sucede porque el operador del indexador se implementa tratando de recuperar el índice de un Colum1 campo que no existe. El método GetOrdinal generará esta excepción cuando su código auxiliar interno devuelva un -1 como índice de "Colum1".
Otros
Hay otro caso (documentado) cuando se lanza esta excepción: si, en
DataView
, el nombre de la columna de datos que se proporciona a laDataViewSort
propiedad no es válido.Como evitar
En este ejemplo, permítanme asumir, por simplicidad, que las matrices son siempre monodimensionales y basadas en 0. Si desea ser estricto (o está desarrollando una biblioteca), es posible que deba reemplazar
0
conGetLowerBound(0)
y.Length
conGetUpperBound(0)
(por supuesto, si tiene parámetros de tipoSystem.Arra
y, no se aplicaT[]
). Tenga en cuenta que en este caso, el límite superior incluye este código:Debería reescribirse así:
Tenga en cuenta que esto no está permitido (arrojará
InvalidCastException
), es por eso que si sus parámetros estánT[]
seguros con respecto a las matrices de límite inferior personalizadas:Validar parámetros
Si el índice proviene de un parámetro, siempre debe validarlos (arrojando el apropiado
ArgumentException
oArgumentOutOfRangeException
). En el siguiente ejemplo, pueden causar parámetros incorrectosIndexOutOfRangeException
, los usuarios de esta función pueden esperar esto porque están pasando una matriz, pero no siempre es tan obvio. Sugeriría validar siempre los parámetros para las funciones públicas:Si la función es privada, simplemente puede reemplazar la
if
lógica conDebug.Assert()
:El
índice Check Object Array puede no venir directamente de un parámetro. Puede ser parte del estado del objeto. En general, siempre es una buena práctica validar el estado del objeto (solo y con parámetros de función, si es necesario). Puede usar
Debug.Assert()
, lanzar una excepción adecuada (más descriptiva sobre el problema) o manejar eso como en este ejemplo:Validar valores de retorno
En uno de los ejemplos anteriores, utilizamos directamente el
Array.IndexOf()
valor de retorno. Si sabemos que puede fallar, entonces es mejor manejar ese caso:Cómo depurar
En mi opinión, la mayoría de las preguntas, aquí en SO, sobre este error pueden simplemente evitarse. El tiempo que dedica a escribir una pregunta adecuada (con un pequeño ejemplo de trabajo y una pequeña explicación) podría ser mucho más que el tiempo que necesitará para depurar su código. En primer lugar, lea esta publicación de blog de Eric Lippert sobre la depuración de pequeños programas , no repetiré sus palabras aquí, pero es absolutamente una lectura obligada .
Tiene código fuente, tiene un mensaje de excepción con un seguimiento de pila. Vaya allí, elija el número de línea correcto y verá:
Encontraste tu error, comprueba cómo
index
aumenta. ¿Es correcto? Compruebe cómo se asigna la matriz, ¿es coherente con cómoindex
aumenta? ¿Es correcto de acuerdo con sus especificaciones? Si tu respondes si a todas estas preguntas, encontrará buena ayuda aquí en StackOverflow, pero primero verifíquelo usted mismo. ¡Ahorrarás tu propio tiempo!Un buen punto de partida es usar siempre aserciones y validar entradas. Es posible que incluso desee utilizar contratos de código. Cuando algo salió mal y no puedes descubrir qué sucede con un vistazo rápido a tu código, entonces tienes que recurrir a un viejo amigo: depurador . Simplemente ejecute su aplicación en depuración dentro de Visual Studio (o su IDE favorito), verá exactamente qué línea arroja esta excepción, qué matriz está involucrada y qué índice está tratando de usar. Realmente, el 99% de las veces lo resolverá usted mismo en unos minutos.
Si esto sucede en producción, será mejor que agregue aserciones en el código incriminado, probablemente no veremos en su código lo que no puede ver usted mismo (pero siempre puede apostar).
El lado VB.NET de la historia
Todo lo que hemos dicho en la respuesta de C # es válido para VB.NET con las diferencias de sintaxis obvias, pero hay un punto importante a tener en cuenta al tratar con matrices de VB.NET.
En VB.NET, las matrices se declaran configurando el valor de índice válido máximo para la matriz. No es el recuento de los elementos que queremos almacenar en la matriz.
Entonces, este bucle llenará la matriz con 5 enteros sin causar ninguna excepción IndexOutOfRangeException
La regla de VB.NET
Esta excepción significa que está intentando acceder a un elemento de colección por índice, utilizando un índice no válido. Un índice no es válido cuando es menor que el límite inferior de la colección o mayor que
igual al número de elementos que contiene.El índice máximo permitido definido en la declaración de matrizfuente
Explicación simple sobre qué es un índice fuera de la excepción encuadernada:
Solo piense que un tren está allí, sus compartimentos son D1, D2, D3. Un pasajero entró al tren y tiene el boleto para D4. ahora que va a pasar. el pasajero desea ingresar a un compartimiento que no existe, por lo que obviamente surgirá un problema.
El mismo escenario: cada vez que intentamos acceder a una lista de matriz, etc., solo podemos acceder a los índices existentes en la matriz.
array[0]
yarray[1]
son existentes Si intentamos accederarray[3]
, en realidad no está allí, por lo que surgirá un índice de excepción vinculada.fuente
Para comprender fácilmente el problema, imagine que escribimos este código:
El resultado será:
El tamaño de la matriz es 3 (índices 0, 1 y 2), pero los bucles for-loop 4 veces (0, 1, 2 y 3).
Entonces, cuando intenta acceder fuera de los límites con (3), arroja la excepción.
fuente
A un lado de la muy completa respuesta aceptada, hay un punto importante que hacer en
IndexOutOfRangeException
comparación con muchos otros tipos de excepciones, y es:A menudo hay un estado de programa complejo que puede ser difícil de controlar en un punto particular del código, por ejemplo, una conexión de base de datos se cae, por lo que los datos de una entrada no se pueden recuperar, etc. Este tipo de problema a menudo resulta en una excepción de algún tipo tiene que burbujear a un nivel superior porque donde ocurre no tiene forma de lidiar con eso en ese punto.
IndexOutOfRangeException
es generalmente diferente en el sentido de que, en la mayoría de los casos, es bastante trivial verificarlo en el punto donde se genera la excepción. En general, este tipo de excepción es arrojado por algún código que podría tratar muy fácilmente el problema en el lugar donde está ocurriendo, simplemente verificando la longitud real de la matriz. No desea 'arreglar' esto manejando esta excepción más arriba, sino asegurándose de que no se lance en primera instancia, lo que en la mayoría de los casos es fácil de hacer al verificar la longitud de la matriz.Otra forma de decir esto es que pueden surgir otras excepciones debido a una genuina falta de control sobre la entrada o el estado del programa, PERO la
IndexOutOfRangeException
mayoría de las veces es simplemente un error piloto (programador).fuente