¿Qué es una IndexOutOfRangeException / ArgumentOutOfRangeException y cómo lo soluciono?

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

Tengo un código y cuando se ejecuta, arroja un mensaje que IndexOutOfRangeExceptiondice:

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.

4 answers

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

¿Qué es?

Esta excepción significa que está intentando acceder a un elemento de la 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 o igual al número de elementos que contiene.

Cuando se lanza

Dada una matriz declarada como:

byte[] array = new byte[4];

Puede acceder a esta matriz de 0 a 3, los valores fuera de este rango harán IndexOutOfRangeExceptionque se arrojen. Recuerde esto cuando cree y acceda a una matriz.

Longitud de la matriz
En C #, normalmente, las matrices están basadas en 0. Significa que el primer elemento tiene índice 0 y el último elemento tiene índice Length - 1(donde Lengthes el número total de elementos en la matriz) por lo que este código no funciona:

array[array.Length] = 0;

Además, tenga en cuenta que si tiene una matriz multidimensional, entonces no puede usar Array.Lengthpara ambas dimensiones, debe usar 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;
    }
}

El límite superior no es inclusivo
En el siguiente ejemplo, creamos una matriz bidimensional sin procesar de Color. Cada elemento representa un píxel, los índices son de (0, 0)a (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;
    }
}

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]:

pixels[imageWidth, imageHeight] = Color.Black;

En otro escenario, puede obtener ArgumentOutOfRangeExceptioneste código (por ejemplo, si está usando un GetPixelmétodo en una Bitmapclase).

Las matrices no crecen
Una matriz es rápida. Muy rápido en la 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 la dirección de la memoria se puede calcular (y el incremento es solo una adición). No es necesario seguir una lista de nodos, ¡matemáticas simples! Usted 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:

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

No olvide que los índices válidos son de 0a Length - 1. Si simplemente intenta asignar un elemento Length, obtendrá IndexOutOfRangeException(este comportamiento puede confundirlo si cree que pueden aumentar con una sintaxis similar al Insertmétodo de otras colecciones).

Matrices especiales con límite inferior personalizado El
primer elemento de las matrices siempre tiene el índice 0 . Esto no siempre es cierto porque puede crear una matriz con un límite inferior personalizado:

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

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 de la función del usuario), puede obtener este error:

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

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

Resultados inesperados
Esta excepción también puede producirse por otra razón: por convención, muchas funciones de búsqueda devolverán -1 (nullables se introdujeron 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 lo hicieron ' No encuentro nada. Imaginemos que tiene una matriz de objetos comparable con una cadena. Puede pensar en escribir este código:

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

Esto fallará si ningún elemento myArraysatisface la condición de búsqueda porque Array.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 dado de números (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):

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

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 arreglo - rango de índices válidos - 0 ( Listlos índices siempre comienzan con 0) para list.Count- acceder a elementos fuera de este rango causará la excepción.

Tenga en cuenta que se List<T>lanza ArgumentOutOfRangeExceptionpara los mismos casos en los que se utilizan matrices IndexOutOfRangeException.

A diferencia de las matrices, List<T>comienza vacío, por lo que intentar acceder a elementos de la lista recién creada conduce a esta excepción.

var list = new List<int>();

El caso común es llenar la lista con indexación (similar a Dictionary<int, T>) causará una excepción:

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

IDataReader y Columns
Imagine que está intentando leer datos de una base de datos con este código:

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()arrojará IndexOutOfRangeExceptionporque su conjunto de datos tiene solo dos columnas, pero está tratando de obtener un valor de la tercera (los índices siempre se basan en 0).

Tenga en cuenta que este comportamiento se comparte con la mayoría de las IDataReaderimplementaciones ( SqlDataReader, OleDbDataReadery así sucesivamente).

También puede obtener la misma excepción si usa la sobrecarga IDataReader del operador indexador que toma un nombre de columna y pasa un nombre de columna no válido.
Supongamos, por ejemplo, que ha recuperado una columna denominada Columna1 pero luego intenta recuperar el valor de ese campo con

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

Esto sucede porque el operador indexador se implementa al intentar recuperar el índice de un campo Colum1 que no existe. El método GetOrdinal lanzará 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 la DataViewSortpropiedad no es válido.

Como evitar

En este ejemplo, déjame suponer, 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 0con GetLowerBound(0)y .Lengthcon GetUpperBound(0)(por supuesto, si tiene parámetros de tipo System.Array, no se aplica T[]). Tenga en cuenta que en este caso, el límite superior es inclusivo y luego este código:

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

Debería reescribirse así:

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

Tenga en cuenta que esto no está permitido (arrojará InvalidCastException), por eso, si sus parámetros son T[], está seguro sobre las matrices personalizadas de límite inferior:

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

Validar parámetros
Si el índice proviene de un parámetro, siempre debe validarlo (arrojando apropiado ArgumentExceptiono ArgumentOutOfRangeException). En el siguiente ejemplo, los parámetros incorrectos pueden causar IndexOutOfRangeException, 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:

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

Si la función es privada, simplemente puede reemplazar la iflógica con Debug.Assert():

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

Es
posible que el índice Check Object State Array no provenga 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 (por sí mismo 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:

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

Validar valores devueltos
En uno de los ejemplos anteriores usamos directamente el Array.IndexOf()valor devuelto. Si sabemos que puede fallar, entonces es mejor manejar ese caso:

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

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) fácilmente podría ser mucho más que el tiempo que necesitará para depurar su código. En primer lugar, lea esta publicación del blog de Eric Lippert sobre la depuración de programas pequeños , no repetiré sus palabras aquí, pero es absolutamente imprescindible .

Tiene código fuente, tiene un mensaje de excepción con un seguimiento de pila. Vaya allí, elija el número de la línea derecha y verá:

array[index] = newValue;

Encontraste tu error, comprueba cómo indexaumenta. ¿Es correcto? Compruebe cómo se asigna la matriz, ¿es coherente con cómo indexaumenta? ¿Está bien de acuerdo con sus especificaciones? Si responde afirmativamente a todas estas preguntas, encontrará una buena ayuda aquí en StackOverflow, pero primero compruébelo usted mismo. ¡Ahorrará su propio tiempo!

Un buen punto de partida es utilizar siempre afirmaciones y validar las entradas. Es posible que incluso desee utilizar contratos de código. Cuando algo salió mal y no puedes averiguar qué sucede con un vistazo rápido a tu código, entonces tienes que recurrir a un viejo amigo: el 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ás tú solo en unos minutos.

Si esto sucede en producción, es mejor que agregue afirmaciones en el código incriminado, probablemente no veremos en su código lo que no puede ver por sí 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 obvias diferencias de sintaxis, pero hay un punto importante a considerar cuando se trata de matrices VB.NET.

En VB.NET, las matrices se declaran estableciendo el valor de índice válido máximo para la matriz. No es el recuento de los elementos que queremos almacenar en la matriz.

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

Entonces este bucle llenará la matriz con 5 enteros sin causar ninguna excepción IndexOutOfRangeException

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

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 queigual al número de elementos que contiene. el índice máximo permitido definido en la declaración de la matriz

20
Lijo 2016-03-05 01:22.

Explicación simple sobre qué es una excepción de índice fuera de límite:

Solo piense que hay un tren allí, sus compartimentos son D1, D2, D3. Un pasajero vino a entrar al tren y tiene el boleto de D4. ahora que va a pasar. el pasajero quiere entrar en un compartimento que no existe por lo que obviamente surgirá un problema.

Mismo escenario: siempre que intentamos acceder a una lista de matrices, etc., solo podemos acceder a los índices existentes en la matriz. array[0]y array[1]existen. Si intentamos acceder array[3], en realidad no está allí, por lo que surgirá una excepción de índice fuera del límite.

10
Snr 2017-12-07 20:48.

Para comprender fácilmente el problema, imagine que escribimos este código:

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

El resultado será:

hello1
hello2
hello3

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

El tamaño de la matriz es 3 (índices 0, 1 y 2), pero el bucle for se repite 4 veces (0, 1, 2 y 3).
Entonces, cuando intenta acceder fuera de los límites con (3) lanza la excepción.

1
Ricibob 2019-03-01 22:51.

Aparte de la respuesta aceptada completa muy larga, hay un punto importante que hacer en IndexOutOfRangeExceptioncomparación con muchos otros tipos de excepciones, y es:

A menudo hay un estado de programa complejo sobre el que puede ser difícil tener control en un punto particular del código, por ejemplo, una conexión de base de datos falla, por lo que los datos de una entrada no se pueden recuperar, etc.Este tipo de problema a menudo da como resultado una excepción de algún tipo que tiene que subir a un nivel superior porque donde ocurre no tiene forma de lidiar con eso en ese punto.

IndexOutOfRangeExceptiones generalmente diferente en que en la mayoría de los casos es bastante trivial verificar en el punto donde se genera la excepción. Generalmente, este tipo de excepción es lanzada por algún código que podría resolver fácilmente el problema en el lugar en el que ocurre, 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 produzca en la 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 expresar esto es que pueden surgir otras excepciones debido a una falta genuina de control sobre la entrada o el estado del programa, PERO la IndexOutOfRangeExceptionmayoría de las veces es simplemente un error piloto (programador).

Related questions

MORE COOL STUFF

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que tiene 'envenenamiento por mercurio y plomo' probablemente por voltear 'casas asquerosas'

La estrella de HGTV, Christina Hall, revela que le diagnosticaron envenenamiento por mercurio y plomo, probablemente debido a su trabajo como manipuladora de casas.

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

La estrella de 'Love Is Blind' Brennon Lemieux responde a los cargos de violencia doméstica

Recientemente salió a la luz un informe policial que acusa a la estrella de 'Love Is Blind', Brennon, de violencia doméstica. Ahora, Brennon ha respondido a los reclamos.

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia Judd en un momento festivo de pánico

Conozca cómo Wynonna Judd se dio cuenta de que ahora es la matriarca de la familia mientras organizaba la primera celebración de Acción de Gracias desde que murió su madre, Naomi Judd.

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Experto en lenguaje corporal explica los 'paralelos' entre Kate Middleton y la princesa Diana

Descubra por qué un destacado experto en lenguaje corporal cree que es fácil trazar "tales paralelismos" entre la princesa Kate Middleton y la princesa Diana.

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los láseres arrojan luz sobre por qué necesita cerrar la tapa antes de descargar

Los inodoros arrojan columnas de aerosol invisibles con cada descarga. ¿Como sabemos? La prueba fue capturada por láseres de alta potencia.

The Secrets of Airline Travel Quiz

The Secrets of Airline Travel Quiz

Air travel is far more than getting from point A to point B safely. How much do you know about the million little details that go into flying on airplanes?

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

¿Caduca el repelente de insectos?

¿Caduca el repelente de insectos?

¿Sigue siendo efectivo ese lote de repelente de insectos que te quedó del verano pasado? Si es así, ¿por cuánto tiempo?

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Estados Unidos podría evitarse el horror del nuevo gran horneado británico

Si este tráiler de pesadilla de la temporada más reciente de Great British Bake Off te asustó y te hizo no volver a ver el programa, es posible que tengas suerte: PBS no ha decidido si se transmitirá o no la última temporada en los Estados Unidos. actualización, para aquellos que no siguen sin aliento este tipo de drama de nicho: el presentador Paul Hollywood y la hermosa carpa llena de batidoras de colores pastel y cuadros se trasladaron de la BBC al Canal 4; Mary Berry, Sue Perkins y Mel Giedroyc renunciaron.

Atún como Oh, Hello llega a Netflix

Atún como Oh, Hello llega a Netflix

Foto: Netflix Oh, Hello On Broadway (Netflix): Después de llegar a Broadway el año pasado, los dos locos del Upper West Side interpretados por John Mulaney y Nick Kroll finalmente llegaron a Netflix. El especial consta del espectáculo en el escenario, algunos momentos entre bastidores y un invitado muy especial de “Too Much Tuna”.

Actualice a un Sonicare por tan solo $ 30

Actualice a un Sonicare por tan solo $ 30

¿Quiere probar un cepillo de dientes Sonicare sin gastar mucho dinero en uno de sus modelos favoritos de gama alta? Puede comprar un kit de la Serie 2 o Serie 3 por tan solo $ 30 hoy en Amazon. Haga clic aquí para ver la lista completa de modelos elegibles y tenga en cuenta que se descontarán $ 10 adicionales en su carrito.

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Ponle una tapa. En realidad, ponle una tapa a todo. Consigue 12 tapas de cocina elásticas de silicona por $14. [Exclusivo]

Tapas elásticas de silicona de Tomorrow's Kitchen, paquete de 12 | $14 | Amazonas | Código promocional 20OFFKINJALids son básicamente los calcetines de la cocina; siempre perdiéndose, dejando contenedores huérfanos que nunca podrán volver a cerrarse. Pero, ¿y si sus tapas pudieran estirarse y adaptarse a todos los recipientes, ollas, sartenes e incluso frutas en rodajas grandes que sobran? Nunca más tendrás que preocuparte por perder esa tapa tan específica.

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

Patinaje artístico de EE. UU. 'frustrado' por falta de decisión final en evento por equipos, pide una decisión justa

El equipo está a la espera de las medallas que ganó en los Juegos Olímpicos de Invierno de 2022 en Beijing, ya que se está resolviendo un caso de dopaje que involucra a la patinadora artística rusa Kamila Valieva.

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Los compradores de Amazon dicen que duermen 'como un bebé mimado' gracias a estas fundas de almohada de seda que cuestan tan solo $ 10

Miles de compradores de Amazon recomiendan la funda de almohada de seda Mulberry, y está a la venta en este momento. La funda de almohada de seda viene en varios colores y ayuda a mantener el cabello suave y la piel clara. Compre las fundas de almohada de seda mientras tienen hasta un 46 por ciento de descuento en Amazon

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

Se busca al corredor de los Bengals Joe Mixon por orden de arresto emitida por presuntamente apuntar con un arma de fuego a una mujer

El jueves se presentó una denuncia de delito menor amenazante agravado contra Joe Mixon.

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

Profesor de la Universidad de Purdue arrestado por presuntamente traficar metanfetamina y proponer favores sexuales a mujeres

El Departamento de Policía de Lafayette comenzó a investigar a un profesor de la Universidad de Purdue en diciembre después de recibir varias denuncias de un "hombre sospechoso que se acercaba a una mujer".

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Concept Drift: el mundo está cambiando demasiado rápido para la IA

Al igual que el mundo que nos rodea, el lenguaje siempre está cambiando. Mientras que en eras anteriores los cambios en el idioma ocurrían durante años o incluso décadas, ahora pueden ocurrir en cuestión de días o incluso horas.

India me está pateando el culo

India me está pateando el culo

Estoy de vuelta por primera vez en seis años. No puedo decirte cuánto tiempo he estado esperando esto.

ℝ

“And a river went out of Eden to water the garden, and from thence it was parted and became into four heads” Genesis 2:10. ? The heart is located in the middle of the thoracic cavity, pointing eastward.

¿Merrick Garland le ha fallado a Estados Unidos?

Es más de la mitad de la presidencia de Biden. ¿Qué está esperando Merrick Garland?

¿Merrick Garland le ha fallado a Estados Unidos?

Creo, un poco tarde en la vida, en dar oportunidades a la gente. Generosamente.

Language