यह क्या है?
इस अपवाद का मतलब है कि आप किसी अमान्य इंडेक्स का उपयोग करके इंडेक्स द्वारा संग्रह आइटम तक पहुंचने का प्रयास कर रहे हैं। जब यह संग्रह की निचली सीमा से कम या इसके तत्वों की संख्या के बराबर या उससे अधिक होता है, तो एक इंडेक्स अमान्य होता है।
जब यह फेंक दिया जाता है
दिए गए एक सरणी को देखते हुए:
byte[] array = new byte[4];
आप इस सरणी को 0 से 3 तक एक्सेस कर सकते हैं, इस सीमा के बाहर के मान IndexOutOfRangeException
फेंक दिए जाएंगे। यह याद रखें जब आप एक सरणी बनाते हैं और उसका उपयोग करते हैं।
सरणी लंबाई
C # में, आमतौर पर, सरणियाँ 0-आधारित होती हैं। इसका अर्थ है कि पहले तत्व का सूचकांक 0 है और अंतिम तत्व का सूचकांक है Length - 1
(जहां)Length
एरे में आइटम की कुल संख्या है) इसलिए यह कोड काम नहीं करता है:
array[array.Length] = 0;
इसके अलावा कृपया ध्यान दें कि यदि आपके पास एक बहुआयामी सरणी है तो आप Array.Length
दोनों आयामों के लिए उपयोग नहीं कर सकते , आपको उपयोग करना होगा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;
}
}
ऊपरी बाउंड इनक्लूसिव नहीं
है निम्नलिखित उदाहरण में हम एक कच्ची बोली-संबंधी सरणी बनाते हैं Color
। प्रत्येक आइटम एक पिक्सेल का प्रतिनिधित्व करता है, सूचकांक से (0, 0)
हैं(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;
}
}
यह कोड तब विफल हो जाएगा क्योंकि छवि में सरणी 0-आधारित और अंतिम (नीचे-दाएं) पिक्सेल है pixels[imageWidth - 1, imageHeight - 1]
:
pixels[imageWidth, imageHeight] = Color.Black;
एक अन्य परिदृश्य में आप ArgumentOutOfRangeException
इस कोड के लिए प्राप्त कर सकते हैं (उदाहरण के लिए यदि आप उपयोग कर रहे हैंGetPixel
किसी Bitmap
वर्ग पर विधि )।
सरणी न बढ़ें
एक सरणी तेज़ है। हर दूसरे संग्रह की तुलना में रैखिक खोज में बहुत तेज है। ऐसा इसलिए है क्योंकि आइटम मेमोरी में सन्निहित हैं इसलिए मेमोरी एड्रेस की गणना की जा सकती है (और वेतन वृद्धि एक अतिरिक्त है)। एक नोड सूची, सरल गणित का पालन करने की आवश्यकता नहीं है! आप इसे एक सीमा के साथ भुगतान करते हैं: वे नहीं बढ़ सकते हैं, यदि आपको अधिक तत्वों की आवश्यकता है तो आपको उस सरणी को फिर से भरना होगा (यदि पुरानी वस्तुओं को एक नए ब्लॉक में कॉपी किया जाना चाहिए) तो यह अपेक्षाकृत लंबा समय लग सकता है। आप उनका आकार बदलते हैं Array.Resize<T>()
, यह उदाहरण मौजूदा सरणी में एक नई प्रविष्टि जोड़ता है:
Array.Resize(ref array, array.Length + 1);
मत भूलो कि वैध सूचकांक से 0
हैं Length - 1
। यदि आप बस किसी आइटम को Length
प्राप्त करने का प्रयास करते हैं तो आप प्राप्त करेंगेIndexOutOfRangeException
(अगर आपको लगता है कि वे के लिए इसी तरह एक वाक्य रचना के साथ वृद्धि हो सकती है इस व्यवहार आप भ्रमित हो सकते हैं Insert
अन्य संग्रह की विधि)।
ऐरे में कस्टम लोअर बाउंड
फर्स्ट आइटम के साथ स्पेशल एरर हमेशा इंडेक्स 0 होता है । यह हमेशा सच नहीं होता क्योंकि आप एक कस्टम लोअर बाउंड के साथ एक सरणी बना सकते हैं:
var array = Array.CreateInstance(typeof(byte), new int[] { 4 }, new int[] { 1 });
उस उदाहरण में, सरणी सूचक 1 से 4 तक मान्य हैं। बेशक, ऊपरी बाध्य को नहीं बदला जा सकता है।
गलत तर्क
यदि आप एक सरणी का उपयोग करते हैं, जो बिना किसी तर्क के उपयोग करती है (उपयोगकर्ता इनपुट या फ़ंक्शन उपयोगकर्ता से) तो आपको यह जानकारी मिल सकती है:
private static string[] RomanNumbers =
new string[] { "I", "II", "III", "IV", "V" };
public static string Romanize(int number)
{
return RomanNumbers[number];
}
अनपेक्षित परिणाम
यह अपवाद किसी अन्य कारण से भी फेंका जा सकता है: कन्वेंशन द्वारा, कई खोज फ़ंक्शंस -1 लौट आएंगे (nullables को .NET 2.0 के साथ पेश किया गया है और वैसे भी यह कई वर्षों से उपयोग में एक प्रसिद्ध सम्मेलन है) टी कुछ भी मिल आइए कल्पना करें कि आपके पास स्ट्रिंग के साथ तुलनीय वस्तुओं की एक सरणी है। आप इस कोड को लिखने के लिए सोच सकते हैं:
// 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")]);
यदि कोई आइटम नहीं है, तो यह विफल हो जाएगा myArray
खोज स्थिति को संतुष्ट करेगा क्योंकि जाएगाArray.IndexOf()
-1 वापस आ जाएगा और फिर सरणी पहुंच फेंक देगा।
अगला उदाहरण संख्याओं के दिए गए सेट की घटनाओं की गणना करने के लिए एक भोली उदाहरण है (अधिकतम संख्या जानने और एक सरणी वापस करने पर जहां सूचकांक 0 पर आइटम नंबर 0 का प्रतिनिधित्व करता है, सूचकांक 1 पर आइटम नंबर 1 का प्रतिनिधित्व करता है और इसी तरह):
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;
}
बेशक, यह एक बहुत ही भयानक कार्यान्वयन है लेकिन मैं जो दिखाना चाहता हूं वह यह है कि यह नकारात्मक संख्याओं और संख्याओं के लिए विफल हो जाएगा maximum
।
यह कैसे लागू होता है List<T>
?
सरणी के रूप में समान मामले - मान्य अनुक्रमित की सीमा - 0 (List
's अनुक्रमित हमेशा 0 से शुरू होती है)list.Count
- इस सीमा के बाहर के तत्वों तक पहुँच अपवाद का कारण होगा।
ध्यान दें कि List<T>
फेंकता हैArgumentOutOfRangeException
उन्हीं मामलों के लिए जहाँ सरणियाँ उपयोग करती हैंIndexOutOfRangeException
।
सरणियों के विपरीत, List<T>
खाली शुरू होता है - इसलिए इस अपवाद के लिए बस बनाई गई सूची के आइटम तक पहुंचने की कोशिश कर रहा है।
var list = new List<int>();
सामान्य मामला अनुक्रमण के साथ सूची को पॉप्युलेट करना है (समान Dictionary<int, T>
) अपवाद का कारण होगा:
list[0] = 42; // exception
list.Add(42); // correct
IDataReader और कॉलम
इस कोड के साथ डेटाबेस से डेटा पढ़ने की कोशिश कर रहे हैं:
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()
फेंक देंगे IndexOutOfRangeException
क्योंकि आप डेटासेट में केवल दो कॉलम हैं, लेकिन आप 3rd वन (इंडेक्स हैं) से मान प्राप्त करने का प्रयास कर रहे हैं हमेशा 0-आधारित होते हैं)।
कृपया ध्यान दें कि यह व्यवहार अधिकांश IDataReader
कार्यान्वयनों के साथ साझा किया गया है ( SqlDataReader
,OleDbDataReader
और इसी तरह)।
आप एक ही अपवाद प्राप्त कर सकते हैं यदि आप अनुक्रमणिका ऑपरेटर के IDataReader अधिभार का उपयोग करते हैं जो एक स्तंभ नाम लेता है और एक अमान्य स्तंभ नाम पारित करता है।
उदाहरण के लिए मान लें कि आपने Column1 नामक एक कॉलम को पुनः प्राप्त कर लिया है, लेकिन फिर आप उस फ़ील्ड के मान को पुनः प्राप्त करने का प्रयास करते हैं
var data = dr["Colum1"]; // Missing the n in Column1.
ऐसा इसलिए होता है क्योंकि अनुक्रमणिका ऑपरेटर को Colum1 के अनुक्रमणिका को पुनः प्राप्त करने के प्रयास में कार्यान्वित किया जाता है फ़ील्ड करता है जो मौजूद नहीं है। गेटऑर्डिनल विधि इस अपवाद को फेंक देगी जब इसका आंतरिक सहायक कोड "Colum1" के सूचकांक के रूप में -1 देता है।
अन्य
इस अपवाद को फेंक दिए जाने पर एक और (प्रलेखित) मामला है: यदि, में DataView
, DataViewSort
संपत्ति को दिया जा रहा डेटा स्तंभ नाम मान्य नहीं है।
कैसे बचें
इस उदाहरण में, मुझे लगता है कि सादगी के लिए, कि सरणियाँ हमेशा अखंड और 0-आधारित होती हैं। आप सख्त होने के लिए (या आप एक पुस्तकालय विकसित कर रहे हैं) चाहते हैं, आप बदलना पड़ सकता है 0
के साथ GetLowerBound(0)
और .Length
साथ GetUpperBound(0)
(बेशक आप प्रकार के पैरामीटर यदि System.Arra
y, इसके लिए लागू नहीं होता T[]
)। कृपया ध्यान दें कि इस मामले में, ऊपरी बाउंड समावेशी है तो यह कोड:
for (int i=0; i < array.Length; ++i) { }
इस तरह से फिर से लिखना चाहिए:
for (int i=array.GetLowerBound(0); i <= array.GetUpperBound(0); ++i) { }
कृपया ध्यान दें कि यह अनुमति नहीं है (इसे फेंक देंगे InvalidCastException
), यही कारण है कि यदि आपके पैरामीटर T[]
कस्टम लोअर बाउंड सरणियों के बारे में सुरक्षित हैं:
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 }));
}
मान्य पैरामीटर
यदि इंडेक्स एक पैरामीटर से आता है तो आपको हमेशा उन्हें मान्य करना चाहिए (उचित ArgumentException
या फेंकना ArgumentOutOfRangeException
)। अगले उदाहरण में, गलत पैरामीटर का कारण हो सकता है IndexOutOfRangeException
, इस फ़ंक्शन के उपयोगकर्ता यह उम्मीद कर सकते हैं क्योंकि वे एक सरणी से गुजर रहे हैं लेकिन यह हमेशा इतना स्पष्ट नहीं होता है। मैं हमेशा सार्वजनिक कार्यों के लिए मापदंडों को मान्य करने का सुझाव दूंगा:
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);
}
यदि फ़ंक्शन निजी है, तो आप केवल if
तर्क को बदल सकते हैं Debug.Assert()
:
Debug.Assert(from >= 0 && from < array.Length);
जाँचें ऑब्जेक्ट स्टेट
एरे इंडेक्स एक पैरामीटर से सीधे नहीं आ सकता है। यह वस्तु स्थिति का हिस्सा हो सकता है। सामान्य तौर पर हमेशा ऑब्जेक्ट स्टेट को सत्यापित करने के लिए एक अच्छा अभ्यास है (यदि आवश्यक हो तो और फ़ंक्शन मापदंडों के साथ)। आप Debug.Assert()
एक उपयुक्त अपवाद का उपयोग कर सकते हैं (समस्या के बारे में अधिक वर्णनात्मक) या इस उदाहरण में इसे संभाल सकते हैं:
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];
}
}
रिटर्न वैल्यू को मान्य करें
पिछले उदाहरणों में से एक में हमने सीधे Array.IndexOf()
रिटर्न वैल्यू का उपयोग किया है । अगर हम जानते हैं कि यह विफल हो सकता है तो उस मामले को संभालना बेहतर होगा:
int index = myArray[Array.IndexOf(myArray, "Debug");
if (index != -1) { } else { }
डीबग कैसे करें
मेरी राय में, इस त्रुटि के बारे में SO पर, यहां अधिकांश प्रश्न, सरलता से टाले जा सकते हैं। जिस समय आप एक उचित प्रश्न (एक छोटे से काम के उदाहरण और एक छोटे से स्पष्टीकरण के साथ) लिखने के लिए बिताते हैं, उस समय से अधिक आसानी से आप अपने कोड को डीबग करने की आवश्यकता होगी। सबसे पहले, छोटे कार्यक्रमों के डिबगिंग के बारे में एरिक लिपर्ट के ब्लॉग पोस्ट को पढ़ें , मैं उनके शब्दों को यहां नहीं दोहराऊंगा लेकिन यह बिल्कुल पढ़ना होगा ।
आपके पास स्रोत कोड है, आपके पास स्टैक ट्रेस के साथ अपवाद संदेश है। वहां जाएं, राइट लाइन नंबर चुनें और आप देखेंगे:
array[index] = newValue;
आपको अपनी त्रुटि मिली, जांचें कि कैसे index
बढ़ती है। क्या यह सही है? चेक करें कि सरणी कैसे आवंटित की जाती है, कैसे index
बढ़ती है के साथ सुसंगत है ? क्या यह आपके विनिर्देशों के अनुसार सही है? यदि आप हाँ में उत्तर देते हैं इन सभी करते हैं, तो आपको यहां StackOverflow पर अच्छी मदद मिलेगी, लेकिन कृपया पहले खुद से इसके लिए जाँच करें। आप अपना समय बचाएंगे!
एक अच्छी शुरुआत बिंदु हमेशा अभिकर्मकों का उपयोग करना और आदानों को मान्य करना है। तुम भी कोड अनुबंध का उपयोग करना चाहते हो सकता है। जब कुछ गलत हुआ और आप यह पता नहीं लगा सकते हैं कि आपके कोड पर त्वरित नज़र के साथ क्या होता है तो आपको एक पुराने दोस्त का सहारा लेना होगा: डीबगर । विजुअल स्टूडियो (या अपने पसंदीदा आईडीई) के अंदर डिबग में बस अपना एप्लिकेशन चलाएं, आप देखेंगे कि वास्तव में कौन सी पंक्ति इस अपवाद को फेंकती है, कौन सी सरणी शामिल है और आप किस सूचकांक का उपयोग करने की कोशिश कर रहे हैं। वास्तव में, 99% बार आप इसे कुछ ही मिनटों में स्वयं हल कर लेंगे।
यदि उत्पादन में ऐसा होता है, तो आप गलत कोड में दावे जोड़ना बेहतर होगा, शायद हम आपके कोड में नहीं देखेंगे कि आप अपने आप को क्या नहीं देख सकते हैं (लेकिन आप हमेशा दांव लगा सकते हैं)।
कहानी का VB.NET पक्ष
हमने C # उत्तर में जो कुछ भी कहा है वह स्पष्ट वाक्यविन्यास अंतर के साथ VB.NET के लिए मान्य है लेकिन जब आप VB.NET सरणियों से निपटते हैं तो विचार करने के लिए एक महत्वपूर्ण बिंदु है।
VB.NET में, सरणी के लिए अधिकतम वैध सूचकांक मान सेट करने के लिए ऐरे को घोषित किया जाता है। यह उन तत्वों की गिनती नहीं है जिन्हें हम सरणी में संग्रहीत करना चाहते हैं।
' declares an array with space for 5 integer
' 4 is the maximum valid index starting from 0 to 4
Dim myArray(4) as Integer
तो यह लूप किसी भी IndexOutOfRangeException के कारण 5 पूर्णांक के साथ सरणी को भर देगा
For i As Integer = 0 To 4
myArray(i) = i
Next
VB.NET नियम
इस अपवाद का मतलब है कि आप किसी अमान्य इंडेक्स का उपयोग करके इंडेक्स द्वारा संग्रह आइटम तक पहुंचने का प्रयास कर रहे हैं। जब यह संग्रह की निचली सीमा से कम या अधिक से अधिक होता है तो एक सूचकांक अमान्य होता हैइसमें मौजूद तत्वों की संख्या के बराबर। सरणी घोषणा में परिभाषित अधिकतम अनुमत सूचकांक