Eu tenho algum código e, quando executado, lança um IndexOutOfRangeException
, dizendo:
O índice estava fora dos limites da matriz.
O que isso significa e o que posso fazer sobre isso?
Dependendo das classes utilizadas, também pode ser ArgumentOutOfRangeException
Ocorreu uma exceção do tipo 'System.ArgumentOutOfRangeException' no mscorlib.dll, mas não foi tratada no código do usuário Informações adicionais: O índice estava fora do intervalo. Deve ser não negativo e menor que o tamanho da coleção.
c#
.net
indexoutofrangeexception
Adriano Repetti
fonte
fonte
Respostas:
O que é isso?
Essa exceção significa que você está tentando acessar um item de coleção por índice, usando um índice inválido. Um índice é inválido quando é menor que o limite inferior da coleção ou maior que ou igual ao número de elementos que ela contém.
Quando é lançado
Dada uma matriz declarada como:
Você pode acessar esse array de 0 a 3, valores fora desse intervalo causarão o
IndexOutOfRangeException
lançamento. Lembre-se disso ao criar e acessar uma matriz.Comprimento da matriz
Em C #, geralmente, as matrizes são baseadas em 0. Isso significa que o primeiro elemento tem índice 0 e o último elemento tem índice
Length - 1
(ondeLength
é o número total de itens na matriz), portanto, esse código não funciona:Além disso, observe que, se você tiver um array multidimensional, não poderá usar as
Array.Length
duas dimensões, precisará usarArray.GetLength()
:O limite superior não é inclusivo
No exemplo a seguir, criamos uma matriz bidimensional bruta de
Color
. Cada item representa um pixel, os índices são de(0, 0)
para(imageWidth - 1, imageHeight - 1)
.Esse código falhará porque a matriz é baseada em 0 e o último pixel (canto inferior direito) da imagem é
pixels[imageWidth - 1, imageHeight - 1]
:Em outro cenário, você pode obter
ArgumentOutOfRangeException
esse código (por exemplo, se você estiver usando oGetPixel
método em umaBitmap
classe).Matrizes não crescem
Uma matriz é rápida. Muito rápido na pesquisa linear em comparação com todas as outras coleções. Como os itens são contíguos na memória, o endereço da memória pode ser calculado (e o incremento é apenas uma adição). Não há necessidade de seguir uma lista de nós, matemática simples! Você paga isso com uma limitação: eles não podem crescer; se você precisar de mais elementos, precisará realocar essa matriz (isso pode levar um tempo relativamente longo se itens antigos precisarem ser copiados para um novo bloco). Você as redimensiona
Array.Resize<T>()
, este exemplo adiciona uma nova entrada a uma matriz existente:Não esqueça que os índices válidos são de
0
paraLength - 1
. Se você simplesmente tentar atribuir um item aoLength
seu destinoIndexOutOfRangeException
(esse comportamento pode confundir você, se você acha que eles podem aumentar com uma sintaxe semelhante aoInsert
método de outras coleções).Matrizes especiais com limite inferior personalizado O
primeiro item das matrizes sempre indexa 0 . Isso nem sempre é verdade porque você pode criar uma matriz com um limite inferior personalizado:
Nesse exemplo, os índices da matriz são válidos de 1 a 4. Obviamente, o limite superior não pode ser alterado.
Argumentos errados
Se você acessar uma matriz usando argumentos não validados (da entrada do usuário ou do usuário da função), poderá receber este erro:
Resultados inesperados
Essa exceção também pode ser lançada por outro motivo: por convenção, muitas funções de pesquisa retornarão -1 (nulos foram introduzidos no .NET 2.0 e, de qualquer forma, também é uma convenção conhecida em uso há muitos anos), se não ocorreram ' Não encontrei nada. Vamos imaginar que você tenha uma variedade de objetos comparáveis a uma string. Você pode escrever esse código:
Isso falhará se nenhum item dentro
myArray
satisfizer a condição de pesquisa porqueArray.IndexOf()
retornará -1 e o acesso ao array será lançado.O próximo exemplo é um exemplo ingênuo para calcular ocorrências de um determinado conjunto de números (saber o número máximo e retornar uma matriz em que o item no índice 0 representa o número 0, os itens no índice 1 representam o número 1 e assim por diante):
Claro, é uma implementação bastante terrível, mas o que eu quero mostrar é que ela falhará nos números negativos e acima
maximum
.Como isso se aplica
List<T>
?Os mesmos casos que o intervalo de matriz de índices válidos - 0 (
List
os índices de sempre começam com 0)list.Count
- o acesso a elementos fora desse intervalo causará a exceção.Observe que
List<T>
lançaArgumentOutOfRangeException
para os mesmos casos em que as matrizes são usadasIndexOutOfRangeException
.Ao contrário de matrizes,
List<T>
começa vazio - portanto, tentar acessar itens da lista recém-criada leva a essa exceção.O caso comum é preencher a lista com indexação (semelhante a
Dictionary<int, T>
) causará exceção:IDataReader e colunas
Imagine que você está tentando ler dados de um banco de dados com este código:
GetString()
será lançadoIndexOutOfRangeException
porque o conjunto de dados tem apenas duas colunas, mas você está tentando obter um valor da terceira (os índices sempre são baseados em 0).Por favor note que este comportamento é compartilhada com a maioria das
IDataReader
implementações (SqlDataReader
,OleDbDataReader
e assim por diante).Você pode obter a mesma exceção também se usar a sobrecarga IDataReader do operador do indexador que pega um nome de coluna e passa um nome de coluna inválido.
Suponha, por exemplo, que você tenha recuperado uma coluna chamada Coluna1, mas tente recuperar o valor desse campo com
Isso acontece porque o operador do indexador é implementado tentando recuperar o índice de um campo Colum1 que não existe. O método GetOrdinal lançará essa exceção quando seu código auxiliar interno retornar -1 como o índice de "Colum1".
Outros
Há outro caso (documentado) em que essa exceção é lançada: se, em
DataView
, o nome da coluna de dados fornecido àDataViewSort
propriedade não for válido.Como evitar
Neste exemplo, deixe-me supor, por simplicidade, que as matrizes são sempre monodimensionais e baseadas em 0. Se você quer ser rigoroso (ou está desenvolvendo uma biblioteca), pode ser necessário substituir
0
porGetLowerBound(0)
e.Length
porGetUpperBound(0)
(é claro que se você tiver parâmetros do tipoSystem.Arra
y, isso não se aplicaT[]
). Observe que, nesse caso, o limite superior é inclusivo e, em seguida, este código:Deve ser reescrito assim:
Observe que isso não é permitido (será lançado
InvalidCastException
); é por isso que, se seus parâmetros estiveremT[]
seguros, você poderá usar matrizes de limite inferior personalizadas:Validar parâmetros
Se o índice der origem de um parâmetro, você sempre deve validá-los (jogando apropriado
ArgumentException
ouArgumentOutOfRangeException
). No próximo exemplo, parâmetros errados podem causarIndexOutOfRangeException
, os usuários dessa função podem esperar isso porque estão passando uma matriz, mas nem sempre é tão óbvio. Eu sugeriria sempre validar parâmetros para funções públicas:Se a função é privada, você pode simplesmente substituir a
if
lógica porDebug.Assert()
:O
índice Check Object State Array pode não vir diretamente de um parâmetro. Pode fazer parte do estado do objeto. Em geral, é sempre uma boa prática validar o estado do objeto (por si só e com parâmetros de função, se necessário). Você pode usar
Debug.Assert()
, lançar uma exceção adequada (mais descritiva sobre o problema) ou lidar com isso como neste exemplo:Validar valores de retorno
Em um dos exemplos anteriores, usamos diretamente o
Array.IndexOf()
valor de retorno. Se sabemos que pode falhar, é melhor lidar com esse caso:Como depurar
Na minha opinião, a maioria das perguntas, aqui no SO, sobre esse erro pode ser simplesmente evitada. O tempo que você gasta para escrever uma pergunta adequada (com um pequeno exemplo de trabalho e uma pequena explicação) pode facilmente muito mais do que o tempo necessário para depurar seu código. Antes de tudo, leia este post de Eric Lippert no blog sobre depuração de pequenos programas , não repetirei suas palavras aqui, mas é absolutamente uma leitura obrigatória .
Você tem código fonte, mensagem de exceção com um rastreamento de pilha. Vá para lá, escolha o número da linha direita e você verá:
Você encontrou seu erro, verifique como
index
aumenta. Está certo? Verifique como a matriz é alocada, é coerente com a forma comoindex
aumenta? Está certo de acordo com suas especificações? Se você responder sim a todas essas perguntas, encontrará uma boa ajuda aqui no StackOverflow, mas verifique isso sozinho. Você economizará seu próprio tempo!Um bom ponto de partida é sempre usar asserções e validar entradas. Você pode até querer usar contratos de código. Quando algo deu errado e você não consegue descobrir o que acontece com uma rápida olhada no seu código, é necessário recorrer a um velho amigo: o depurador . Basta executar seu aplicativo em depuração no Visual Studio (ou seu IDE favorito), você verá exatamente qual linha lança essa exceção, qual matriz está envolvida e qual índice você está tentando usar. Realmente, 99% das vezes você resolverá sozinho em alguns minutos.
Se isso acontecer na produção, é melhor adicionar asserções no código incriminado, provavelmente não veremos no seu código o que você não pode ver por si mesmo (mas você sempre pode apostar).
O lado VB.NET da história
Tudo o que dissemos na resposta C # é válido para o VB.NET com as óbvias diferenças de sintaxe, mas há um ponto importante a ser considerado quando você lida com matrizes do VB.NET.
No VB.NET, as matrizes são declaradas definindo o valor máximo de índice válido para a matriz. Não é a contagem dos elementos que queremos armazenar na matriz.
Portanto, esse loop preencherá a matriz com 5 números inteiros sem causar nenhum IndexOutOfRangeException
A regra do VB.NET
Essa exceção significa que você está tentando acessar um item de coleção por índice, usando um índice inválido. Um índice é inválido quando é menor que o limite inferior da coleção ou maior que
igual ao número de elementos que ele contém.o índice máximo permitido definido na declaração da matrizfonte
Explicação simples sobre o que é uma exceção fora do limite do Index:
Apenas pense que um trem está lá, seus compartimentos são D1, D2, D3. Um passageiro entrou no trem e ele tem a passagem para o D4. agora o que vai acontecer. o passageiro deseja entrar em um compartimento que não existe, portanto, obviamente, surgirá um problema.
Mesmo cenário: sempre que tentamos acessar uma lista de matrizes, etc., podemos acessar apenas os índices existentes na matriz.
array[0]
earray[1]
existem. Se tentarmos acessararray[3]
, ele não está lá, na verdade, portanto, um índice fora de exceção surgirá.fonte
Para entender facilmente o problema, imagine que escrevemos este código:
O resultado será:
O tamanho da matriz é 3 (índices 0, 1 e 2), mas o loop for dá laçadas 4 vezes (0, 1, 2 e 3).
Portanto, quando tenta acessar fora dos limites com (3), lança a exceção.
fonte
Um lado da resposta aceita muito longa e completa, há um ponto importante a ser discutido em
IndexOutOfRangeException
comparação com muitos outros tipos de exceção, e é:Freqüentemente, existe um estado complexo do programa que talvez seja difícil de controlar em um ponto específico do código, por exemplo, uma conexão com o banco de dados fica inativa para que os dados de uma entrada não possam ser recuperados, etc ... Esse tipo de problema geralmente resulta em uma exceção de algum tipo que precisa subir a um nível mais alto porque, onde ocorre, não há como lidar com isso nesse ponto.
IndexOutOfRangeException
geralmente é diferente, pois na maioria dos casos é bastante trivial verificar no ponto em que a exceção está sendo gerada. Geralmente, esse tipo de exceção é acionado por algum código que poderia lidar muito facilmente com o problema no local em que está ocorrendo - apenas verificando o comprimento real da matriz. Você não deseja 'consertar' isso lidando com essa exceção mais alto - mas, ao invés disso, garantindo que ela não seja lançada na primeira instância - o que, na maioria dos casos, é fácil, verificando o comprimento da matriz.Outra maneira de colocar isso é que outras exceções podem surgir devido à falta genuína de controle sobre o estado da entrada ou do programa, mas, na
IndexOutOfRangeException
maioria das vezes, é simplesmente um erro do piloto (programador).fonte