Saya memiliki beberapa kode dan ketika dijalankan, ia melempar IndexOutOfRangeException
, mengatakan,
Indeks melewati batas susunan.
Apa artinya ini, dan apa yang bisa saya lakukan?
Tergantung pada kelas yang digunakan, bisa juga ArgumentOutOfRangeException
Pengecualian dari tipe 'System.ArgumentOutOfRangeException' terjadi di mscorlib.dll tetapi tidak ditangani dalam kode pengguna Informasi tambahan: Indeks berada di luar jangkauan. Harus non-negatif dan kurang dari ukuran koleksi.
c#
.net
indexoutofrangeexception
Adriano Repetti
sumber
sumber
Jawaban:
Apa itu?
Pengecualian ini berarti Anda mencoba mengakses item koleksi berdasarkan indeks, menggunakan indeks yang tidak valid. Indeks tidak valid jika lebih rendah dari batas bawah koleksi atau lebih besar dari atau sama dengan jumlah elemen yang dikandungnya.
Saat Dilempar
Diberikan array yang dinyatakan sebagai:
Anda dapat mengakses array ini dari 0 hingga 3, nilai di luar rentang ini akan menyebabkan
IndexOutOfRangeException
dilemparkan. Ingat ini ketika Anda membuat dan mengakses array.Panjang Array
Dalam C #, biasanya, array berbasis 0. Ini berarti bahwa elemen pertama memiliki indeks 0 dan elemen terakhir memiliki indeks
Length - 1
(di manaLength
jumlah total item dalam array) sehingga kode ini tidak berfungsi:Selain itu harap dicatat bahwa jika Anda memiliki array multidimensi maka Anda tidak dapat menggunakan
Array.Length
untuk kedua dimensi, Anda harus menggunakanArray.GetLength()
:Batas Atas Tidak Termasuk
Dalam contoh berikut ini kami membuat array dua dimensi mentah
Color
. Setiap item mewakili pixel, indeks adalah dari(0, 0)
ke(imageWidth - 1, imageHeight - 1)
.Kode ini kemudian akan gagal karena array berbasis 0 dan piksel terakhir (kanan bawah) pada gambar adalah
pixels[imageWidth - 1, imageHeight - 1]
:Dalam skenario lain Anda mungkin mendapatkan
ArgumentOutOfRangeException
kode ini (misalnya jika Anda menggunakanGetPixel
metode diBitmap
kelas).Array Jangan Tumbuh
Array cepat. Sangat cepat dalam pencarian linear dibandingkan dengan setiap koleksi lainnya. Itu karena item berdekatan dalam memori sehingga alamat memori dapat dihitung (dan penambahan hanyalah tambahan). Tidak perlu mengikuti daftar simpul, matematika sederhana! Anda membayar ini dengan batasan: mereka tidak dapat tumbuh, jika Anda membutuhkan lebih banyak elemen, Anda perlu realokasi array itu (ini mungkin memakan waktu yang relatif lama jika item lama harus disalin ke blok baru). Anda mengubah ukurannya dengan
Array.Resize<T>()
, contoh ini menambahkan entri baru ke array yang ada:Jangan lupa bahwa indeks yang valid dari
0
keLength - 1
. Jika Anda hanya mencoba menetapkan item padaLength
Anda akan mendapatkanIndexOutOfRangeException
(perilaku ini dapat membingungkan Anda jika Anda berpikir mereka dapat meningkat dengan sintaksis yang mirip denganInsert
metode koleksi lain).Array Khusus Dengan Kustom Batas Bawah
Item pertama dalam array selalu indeks 0 . Ini tidak selalu benar karena Anda dapat membuat array dengan batas bawah khusus:
Dalam contoh itu, indeks array valid dari 1 hingga 4. Tentu saja, batas atas tidak dapat diubah.
Argumen Salah
Jika Anda mengakses array menggunakan argumen yang tidak divalidasi (dari input pengguna atau dari pengguna fungsi) Anda mungkin mendapatkan kesalahan ini:
Hasil yang Tidak Terduga
Pengecualian ini mungkin dilemparkan karena alasan lain juga: berdasarkan konvensi, banyak fungsi pencarian akan mengembalikan -1 (nullables telah diperkenalkan dengan .NET 2.0 dan lagi pula itu juga merupakan konvensi terkenal yang digunakan selama bertahun-tahun) jika mereka tidak melakukannya. tidak menemukan apa pun. Mari kita bayangkan Anda memiliki array objek yang sebanding dengan string Anda mungkin berpikir untuk menulis kode ini:
Ini akan gagal jika tidak ada item dalam
myArray
akan memenuhi kondisi pencarian karenaArray.IndexOf()
akan mengembalikan -1 dan kemudian akses array akan melempar.Contoh berikutnya adalah contoh naif untuk menghitung kemunculan himpunan angka tertentu (mengetahui angka maksimum dan mengembalikan array di mana item pada indeks 0 mewakili angka 0, item pada indeks 1 mewakili angka 1 dan seterusnya):
Tentu saja, ini adalah implementasi yang sangat mengerikan tetapi yang ingin saya tunjukkan adalah bahwa itu akan gagal untuk angka negatif dan angka di atas
maximum
.Bagaimana ini berlaku untuk
List<T>
?Kasing yang sama dengan array - rentang indeks yang valid - 0 (
List
indeks selalu dimulai dengan 0) untuklist.Count
mengakses elemen di luar rentang ini akan menyebabkan pengecualian.Perhatikan bahwa
List<T>
lemparanArgumentOutOfRangeException
untuk kasus yang sama di mana array digunakanIndexOutOfRangeException
.Tidak seperti array,
List<T>
mulai kosong - jadi mencoba mengakses item dari daftar yang baru saja dibuat mengarah ke pengecualian ini.Kasus umum adalah mengisi daftar dengan pengindeksan (mirip dengan
Dictionary<int, T>
) akan menyebabkan pengecualian:IDataReader dan Kolom
Bayangkan Anda mencoba membaca data dari database dengan kode ini:
GetString()
akan melemparIndexOutOfRangeException
karena dataset Anda hanya memiliki dua kolom tetapi Anda mencoba untuk mendapatkan nilai dari yang ketiga (indeks selalu berbasis 0).Harap dicatat bahwa perilaku ini dibagikan dengan sebagian besar
IDataReader
implementasi (SqlDataReader
,OleDbDataReader
dan sebagainya).Anda bisa mendapatkan pengecualian yang sama juga jika Anda menggunakan IDataReader overload dari operator pengindeks yang mengambil nama kolom dan meneruskan nama kolom yang tidak valid.
Misalkan misalnya Anda telah mengambil kolom bernama Column1 tetapi kemudian Anda mencoba mengambil nilai bidang itu dengan
Ini terjadi karena operator pengindeks dilaksanakan mencoba mengambil indeks dari Colum1 bidang yang tidak ada. Metode GetOrdinal akan melempar pengecualian ini ketika kode pembantu internal mengembalikan -1 sebagai indeks "Colum1".
Lainnya
Ada kasus lain (terdokumentasi) ketika pengecualian ini dilemparkan: jika, dalam
DataView
, nama kolom data yang dipasok keDataViewSort
properti tidak valid.Cara Menghindari
Dalam contoh ini, izinkan saya berasumsi, untuk kesederhanaan, bahwa array selalu berbasis monodimensi dan 0. Jika Anda ingin ketat (atau Anda sedang mengembangkan perpustakaan), Anda mungkin perlu mengganti
0
denganGetLowerBound(0)
dan.Length
denganGetUpperBound(0)
(tentu saja jika Anda memiliki parameter tipeSystem.Arra
y, itu tidak berlaku untukT[]
). Harap perhatikan bahwa dalam hal ini, batas atas inklusif maka kode ini:Harus ditulis ulang seperti ini:
Harap perhatikan bahwa ini tidak diperbolehkan (itu akan melempar
InvalidCastException
), itu sebabnya jika parameterT[]
Anda aman tentang array batas bawah khusus:Validasikan Parameter
Jika indeks berasal dari parameter, Anda harus selalu memvalidasinya (melempar sesuai
ArgumentException
atauArgumentOutOfRangeException
). Dalam contoh berikut, parameter yang salah dapat menyebabkanIndexOutOfRangeException
, pengguna fungsi ini dapat mengharapkan ini karena mereka melewati array tetapi tidak selalu begitu jelas. Saya sarankan untuk selalu memvalidasi parameter untuk fungsi publik:Jika fungsi bersifat pribadi, Anda cukup mengganti
if
logika denganDebug.Assert()
:Periksa Object State
Array index mungkin tidak datang langsung dari parameter. Ini mungkin bagian dari status objek. Secara umum selalu merupakan praktik yang baik untuk memvalidasi keadaan objek (dengan sendirinya dan dengan parameter fungsi, jika diperlukan). Anda dapat menggunakan
Debug.Assert()
, melempar pengecualian yang tepat (lebih deskriptif tentang masalah) atau mengatasinya seperti dalam contoh ini:Validasi Nilai Pengembalian
Dalam salah satu contoh sebelumnya, kami secara langsung menggunakan
Array.IndexOf()
nilai balik. Jika kita tahu itu mungkin gagal maka lebih baik untuk menangani kasus itu:Bagaimana cara Debug
Menurut pendapat saya, sebagian besar pertanyaan, di sini di SO, tentang kesalahan ini bisa dihindari. Waktu yang Anda habiskan untuk menulis pertanyaan yang tepat (dengan contoh kerja kecil dan sedikit penjelasan) dapat dengan mudah lebih dari waktu yang Anda perlukan untuk men-debug kode Anda. Pertama-tama, baca posting blog Eric Lippert ini tentang debugging program kecil , saya tidak akan mengulangi kata-katanya di sini tapi itu benar-benar harus dibaca .
Anda memiliki kode sumber, Anda memiliki pesan pengecualian dengan jejak tumpukan. Pergi ke sana, pilih nomor baris kanan dan Anda akan melihat:
Anda menemukan kesalahan Anda, periksa bagaimana
index
peningkatannya. Apakah tepat? Periksa bagaimana array dialokasikan, apakah koheren denganindex
peningkatan? Apakah benar sesuai dengan spesifikasi Anda? Jika Anda menjawab ya untuk semua pertanyaan ini, maka Anda akan menemukan bantuan yang baik di sini di StackOverflow tapi tolong periksa dulu sendiri. Anda akan menghemat waktu Anda sendiri!Titik awal yang baik adalah untuk selalu menggunakan pernyataan dan untuk memvalidasi input. Anda bahkan mungkin ingin menggunakan kontrak kode. Ketika terjadi kesalahan dan Anda tidak dapat mengetahui apa yang terjadi dengan melihat kode Anda dengan cepat maka Anda harus beralih ke teman lama: debugger . Cukup jalankan aplikasi Anda dalam debug di dalam Visual Studio (atau IDE favorit Anda), Anda akan melihat baris mana yang melempar pengecualian ini, array mana yang terlibat dan indeks mana yang Anda coba gunakan. Sungguh, 99% dari waktu Anda akan menyelesaikannya sendiri dalam beberapa menit.
Jika ini terjadi dalam produksi maka Anda sebaiknya menambahkan pernyataan dalam kode yang memberatkan, mungkin kami tidak akan melihat dalam kode Anda apa yang tidak dapat Anda lihat sendiri (tetapi Anda selalu bisa bertaruh).
Sisi VB.NET dari cerita ini
Segala sesuatu yang telah kami katakan dalam jawaban C # valid untuk VB.NET dengan perbedaan sintaks yang jelas tetapi ada poin penting untuk dipertimbangkan ketika Anda berurusan dengan array VB.NET.
Di VB.NET, array dinyatakan menetapkan nilai indeks valid maksimum untuk array. Bukan hitungan elemen yang ingin kita simpan dalam array.
Jadi loop ini akan mengisi array dengan 5 integer tanpa menyebabkan IndexOutOfRangeException
Aturan VB.NET
Pengecualian ini berarti Anda mencoba mengakses item koleksi berdasarkan indeks, menggunakan indeks yang tidak valid. Indeks tidak valid jika lebih rendah dari batas bawah koleksi atau lebih besar dari
sama dengan jumlah elemen yang dikandungnya.indeks maksimum yang diizinkan didefinisikan dalam deklarasi arraysumber
Penjelasan sederhana tentang apa Indeks keluar dari batas adalah:
Bayangkan satu kereta ada kompartemennya D1, D2, D3. Satu penumpang datang untuk memasuki kereta dan dia memiliki tiket untuk D4. sekarang apa yang akan terjadi penumpang ingin memasuki kompartemen yang tidak ada sehingga jelas masalah akan muncul.
Skenario yang sama: setiap kali kita mencoba mengakses daftar array, dll. Kita hanya dapat mengakses indeks yang ada dalam array.
array[0]
danarray[1]
ada. Jika kami mencoba mengaksesarray[3]
, sebenarnya tidak ada di sana, jadi indeks yang keluar dari pengecualian akan muncul.sumber
Untuk memahami masalahnya dengan mudah, bayangkan kami menulis kode ini:
Hasilnya adalah:
Ukuran array adalah 3 (indeks 0, 1 dan 2), tetapi loop for-loop 4 kali (0, 1, 2 dan 3).
Jadi ketika mencoba mengakses di luar batas dengan (3) ia melempar pengecualian.
sumber
Sisi dari jawaban yang diterima sangat lama ada poin penting untuk
IndexOutOfRangeException
dibandingkan dengan banyak jenis pengecualian lainnya, dan itu adalah:Seringkali ada keadaan program yang kompleks yang mungkin sulit untuk memiliki kontrol pada titik tertentu dalam kode misalnya koneksi DB turun sehingga data untuk input tidak dapat diambil dll ... Masalah seperti ini sering mengakibatkan Pengecualian dari beberapa jenis yang harus menggelembung ke tingkat yang lebih tinggi karena ketika itu terjadi tidak ada cara untuk menghadapinya pada saat itu.
IndexOutOfRangeException
umumnya berbeda karena dalam banyak kasus itu cukup sepele untuk memeriksa pada titik di mana pengecualian sedang diajukan. Umumnya pengecualian semacam ini dilemparkan oleh beberapa kode yang dapat dengan mudah menangani masalah di tempat itu terjadi - hanya dengan memeriksa panjang aktual array. Anda tidak ingin 'memperbaiki' ini dengan menangani pengecualian ini lebih tinggi - tetapi dengan memastikannya tidak dilemparkan pada contoh pertama - yang dalam banyak kasus mudah dilakukan dengan memeriksa panjang array.Cara lain untuk menempatkan ini adalah bahwa pengecualian lain dapat muncul karena kurangnya kontrol atas input atau status program TETAPI
IndexOutOfRangeException
lebih sering daripada tidak hanya kesalahan pilot (programmer).sumber