J'ai du code et quand il s'exécute, il lance un IndexOutOfRangeException
, disant,
L'index était en dehors des limites du tableau.
Qu'est-ce que cela signifie et que puis-je faire?
Selon les classes utilisées, il peut également être ArgumentOutOfRangeException
Une exception de type «System.ArgumentOutOfRangeException» s'est produite dans mscorlib.dll mais n'a pas été gérée dans le code utilisateur. Informations supplémentaires: l'index était hors limites. Doit être non négatif et inférieur à la taille de la collection.
c#
.net
indexoutofrangeexception
Adriano Repetti
la source
la source
Réponses:
Qu'Est-ce que c'est?
Cette exception signifie que vous essayez d'accéder à un élément de collection par index, en utilisant un index non valide. Un index n'est pas valide lorsqu'il est inférieur à la limite inférieure de la collection ou supérieur ou égal au nombre d'éléments qu'il contient.
Quand il est jeté
Étant donné un tableau déclaré comme:
Vous pouvez accéder à ce tableau de 0 à 3, les valeurs en dehors de cette plage entraîneront
IndexOutOfRangeException
la levée. Souvenez-vous de cela lorsque vous créez et accédez à un tableau.Longueur du tableau
En C #, généralement, les tableaux sont basés sur 0. Cela signifie que le premier élément a l'index 0 et le dernier élément a l'index
Length - 1
(oùLength
est le nombre total d'éléments dans le tableau) donc ce code ne fonctionne pas:De plus, veuillez noter que si vous avez un tableau multidimensionnel, vous ne pouvez pas utiliser
Array.Length
pour les deux dimensions, vous devez utiliserArray.GetLength()
:La limite supérieure n'est pas inclusive
Dans l'exemple suivant, nous créons un tableau bidimensionnel brut de
Color
. Chaque élément représente un pixel, les indices vont de(0, 0)
à(imageWidth - 1, imageHeight - 1)
.Ce code échouera alors car le tableau est basé sur 0 et le dernier pixel (en bas à droite) de l'image est
pixels[imageWidth - 1, imageHeight - 1]
:Dans un autre scénario, vous pouvez obtenir
ArgumentOutOfRangeException
ce code (par exemple, si vous utilisez uneGetPixel
méthode sur uneBitmap
classe).Les tableaux ne grandissent pas
Un tableau est rapide. Recherche linéaire très rapide par rapport à toutes les autres collections. C'est parce que les éléments sont contigus dans la mémoire afin que l'adresse mémoire puisse être calculée (et l'incrémentation n'est qu'un ajout). Pas besoin de suivre une liste de nœuds, des maths simples! Vous payez cela avec une limitation: ils ne peuvent pas grandir, si vous avez besoin de plus d'éléments, vous devez réallouer ce tableau (cela peut prendre un temps relativement long si les anciens éléments doivent être copiés dans un nouveau bloc). Vous les redimensionnez avec
Array.Resize<T>()
, cet exemple ajoute une nouvelle entrée à un tableau existant:N'oubliez pas que les indices valides vont de
0
àLength - 1
. Si vous essayez simplement d'attribuer un élément àLength
ce que vous obtiendrezIndexOutOfRangeException
(ce comportement peut vous dérouter si vous pensez qu'ils peuvent augmenter avec une syntaxe similaire à laInsert
méthode d'autres collections).Tableaux spéciaux avec limite inférieure personnalisée Le
premier élément des tableaux a toujours l'index 0 . Ce n'est pas toujours vrai car vous pouvez créer un tableau avec une limite inférieure personnalisée:
Dans cet exemple, les indices de tableau sont valides de 1 à 4. Bien entendu, la limite supérieure ne peut pas être modifiée.
Arguments incorrects
Si vous accédez à un tableau en utilisant des arguments non validés (à partir de l'entrée utilisateur ou de l'utilisateur de la fonction), vous pouvez obtenir cette erreur:
Résultats inattendus
Cette exception peut être lancée pour une autre raison également: par convention, de nombreuses fonctions de recherche renverront -1 (nullables a été introduit avec .NET 2.0 et de toute façon c'est aussi une convention bien connue en usage depuis de nombreuses années) si elles ne l'ont pas fait ' rien trouver. Imaginons que vous ayez un tableau d'objets comparable à une chaîne. Vous pourriez penser à écrire ce code:
Cela échouera si aucun élément dans
myArray
ne satisfait la condition de recherche carArray.IndexOf()
retournera -1 et l'accès au tableau sera renvoyé.L'exemple suivant est un exemple naïf pour calculer les occurrences d'un ensemble donné de nombres (connaissant le nombre maximum et renvoyant un tableau où l'élément à l'index 0 représente le numéro 0, les éléments à l'index 1 représentent le numéro 1 et ainsi de suite):
Bien sûr, c'est une implémentation assez terrible, mais ce que je veux montrer, c'est qu'elle échouera pour les nombres négatifs et les nombres ci-dessus
maximum
.Comment cela s'applique-t-il
List<T>
?Mêmes cas que tableau - plage d'index valides - 0 (
List
les index commencent toujours par 0) pourlist.Count
- accéder aux éléments en dehors de cette plage provoquera l'exception.Notez que
List<T>
lanceArgumentOutOfRangeException
pour les mêmes cas où les tableaux utilisentIndexOutOfRangeException
.Contrairement aux tableaux,
List<T>
commence vide - donc essayer d'accéder aux éléments de la liste qui vient d'être créée conduit à cette exception.Le cas courant est de remplir la liste avec une indexation (similaire à
Dictionary<int, T>
) provoquera une exception:IDataReader et colonnes
Imaginez que vous essayez de lire des données à partir d'une base de données avec ce code:
GetString()
lanceraIndexOutOfRangeException
parce que votre ensemble de données n'a que deux colonnes mais que vous essayez d'obtenir une valeur à partir de la troisième (les indices sont toujours basés sur 0).S'il vous plaît noter que ce comportement est partagé avec la plupart des
IDataReader
implémentations (SqlDataReader
,OleDbDataReader
etc.).Vous pouvez également obtenir la même exception si vous utilisez la surcharge IDataReader de l'opérateur d'indexeur qui prend un nom de colonne et transmet un nom de colonne non valide.
Supposons par exemple que vous ayez récupéré une colonne nommée Colonne1 mais que vous essayez ensuite de récupérer la valeur de ce champ avec
Cela se produit car l'opérateur d'indexation est implémenté en essayant de récupérer l'index d'un champ Colum1 qui n'existe pas. La méthode GetOrdinal lèvera cette exception lorsque son code d'assistance interne renvoie un -1 comme index de "Colum1".
Autres
Il existe un autre cas (documenté) lorsque cette exception est levée: si, dans
DataView
, le nom de la colonne de données fourni à laDataViewSort
propriété n'est pas valide.Comment éviter
Dans cet exemple, laissez-moi supposer, pour simplifier, que les tableaux sont toujours monodimensionnels et basés sur 0. Si vous voulez être strict (ou que vous développez une bibliothèque), vous devrez peut-être remplacer
0
parGetLowerBound(0)
et.Length
parGetUpperBound(0)
(bien sûr, si vous avez des paramètres de typeSystem.Arra
y, cela ne s'applique pasT[]
). Veuillez noter que dans ce cas, la limite supérieure est inclusive alors ce code:Devrait être réécrit comme ceci:
Veuillez noter que cela n'est pas autorisé (cela lancera
InvalidCastException
), c'est pourquoi si vos paramètres sontT[]
sûrs, vous êtes en sécurité avec les tableaux de limites inférieures personnalisés:Valider les paramètres
Si l'index provient d'un paramètre, vous devez toujours les valider (en lançant approprié
ArgumentException
ouArgumentOutOfRangeException
). Dans l'exemple suivant, des paramètres incorrects peuvent provoquerIndexOutOfRangeException
, les utilisateurs de cette fonction peuvent s'y attendre car ils passent un tableau, mais ce n'est pas toujours aussi évident. Je suggère de toujours valider les paramètres pour les fonctions publiques:Si la fonction est privée, vous pouvez simplement remplacer la
if
logique parDebug.Assert()
:Vérifier l'état de l'objet L'
index du tableau peut ne pas provenir directement d'un paramètre. Cela peut faire partie de l'état de l'objet. En général, il est toujours recommandé de valider l'état de l'objet (seul et avec des paramètres de fonction, si nécessaire). Vous pouvez utiliser
Debug.Assert()
, lancer une exception appropriée (plus descriptive sur le problème) ou gérer cela comme dans cet exemple:Valider les valeurs de retour
Dans l'un des exemples précédents, nous avons utilisé directement la
Array.IndexOf()
valeur de retour. Si nous savons que cela peut échouer, il est préférable de gérer ce cas:Comment déboguer
À mon avis, la plupart des questions, ici sur SO, à propos de cette erreur peuvent être simplement évitées. Le temps que vous passez à écrire une question appropriée (avec un petit exemple de travail et une petite explication) pourrait facilement beaucoup plus que le temps dont vous aurez besoin pour déboguer votre code. Tout d'abord, lisez ce billet de blog d'Eric Lippert sur le débogage de petits programmes , je ne répéterai pas ses mots ici mais c'est absolument à lire .
Vous avez le code source, vous avez un message d'exception avec une trace de pile. Allez-y, choisissez le bon numéro de ligne et vous verrez:
Vous avez trouvé votre erreur, vérifiez comment
index
augmente. Est ce juste? Vérifiez comment le tableau est alloué, est cohérent avec la façon dont lesindex
augmentations? Est-ce conforme à vos spécifications? Si vous répondez oui à toutes ces questions, vous trouverez une bonne aide ici sur StackOverflow, mais veuillez d'abord vérifier cela par vous-même. Vous économiserez votre temps!Un bon point de départ est de toujours utiliser des assertions et de valider les entrées. Vous pouvez même utiliser des contrats de code. Quand quelque chose ne va pas et que vous ne pouvez pas comprendre ce qui se passe avec un rapide coup d'œil à votre code, vous devez recourir à un vieil ami: le débogueur . Exécutez simplement votre application en mode débogage dans Visual Studio (ou votre IDE préféré), vous verrez exactement quelle ligne lève cette exception, quel tableau est impliqué et quel index vous essayez d'utiliser. Vraiment, 99% des fois, vous le résoudrez vous-même en quelques minutes.
Si cela se produit en production, vous feriez mieux d'ajouter des assertions dans le code incriminé, nous ne verrons probablement pas dans votre code ce que vous ne pouvez pas voir par vous-même (mais vous pouvez toujours parier).
Le côté VB.NET de l'histoire
Tout ce que nous avons dit dans la réponse C # est valide pour VB.NET avec les différences de syntaxe évidentes, mais il y a un point important à considérer lorsque vous traitez avec des tableaux VB.NET.
Dans VB.NET, les tableaux sont déclarés en définissant la valeur d'index valide maximale pour le tableau. Ce n'est pas le nombre d'éléments que nous voulons stocker dans le tableau.
Donc, cette boucle remplira le tableau avec 5 entiers sans provoquer d' exception IndexOutOfRangeException
La règle VB.NET
Cette exception signifie que vous essayez d'accéder à un élément de collection par index, en utilisant un index non valide. Un index n'est pas valide lorsqu'il est inférieur à la limite inférieure de la collection ou supérieur à
égal au nombre d'éléments qu'il contient.l'index maximum autorisé défini dans la déclaration du tableaula source
Explication simple sur ce qu'est une exception Index hors limite:
Il suffit de penser qu'un train est là, ses compartiments sont D1, D2, D3. Un passager est venu entrer dans le train et il a le billet pour le D4. maintenant ce qui va se passer. le passager veut entrer dans un compartiment qui n'existe pas, donc évidemment un problème se posera.
Même scénario: chaque fois que nous essayons d'accéder à une liste de tableaux, etc., nous ne pouvons accéder qu'aux index existants dans le tableau.
array[0]
etarray[1]
existent. Si nous essayons d'accéderarray[3]
, ce n'est pas là en fait, donc un index hors limite se produira.la source
Pour comprendre facilement le problème, imaginez que nous ayons écrit ce code:
Le résultat sera:
La taille du tableau est de 3 (indices 0, 1 et 2), mais la boucle for boucle 4 fois (0, 1, 2 et 3).
Ainsi, quand il essaie d'accéder en dehors des limites avec (3), il lève l'exception.
la source
À côté de la très longue réponse complète acceptée, il y a un point important à faire par
IndexOutOfRangeException
rapport à de nombreux autres types d'exceptions, à savoir:Il y a souvent un état de programme complexe sur lequel il est peut-être difficile de contrôler à un moment donné du code, par exemple une connexion de base de données tombe en panne, de sorte que les données d'une entrée ne peuvent pas être récupérées, etc. Ce type de problème entraîne souvent une exception qui doit remonter à un niveau supérieur parce que là où cela se produit n'a aucun moyen de le gérer à ce moment-là.
IndexOutOfRangeException
est généralement différent en ce que dans la plupart des cas, il est assez simple de vérifier au moment où l'exception est levée. Généralement, ce type d'exception est levé par un code qui pourrait très facilement résoudre le problème à l'endroit où il se produit - simplement en vérifiant la longueur réelle du tableau. Vous ne voulez pas «corriger» cela en gérant cette exception plus haut - mais plutôt en vous assurant qu'elle ne soit pas lancée en première instance - ce qui est dans la plupart des cas facile à faire en vérifiant la longueur du tableau.Une autre façon d'exprimer cela est que d'autres exceptions peuvent survenir en raison d'un véritable manque de contrôle sur l'entrée ou l'état du programme MAIS le
IndexOutOfRangeException
plus souvent, il s'agit simplement d'une erreur du pilote (programmeur).la source