Dictionary vs Hashtable: C# कलेक्शंस की जंग
\n\nएक परिदृश्य की कल्पना करें: आप C# में कोड लिख रहे हैं, और आपको डेटा को की-वैल्यू के रूप में तेज़ी से सेव और एक्सेस करना है। आप डॉक्यूमेंटेशन खोलते हैं और दो समान क्लास देखते हैं — Dictionary और Hashtable। दोनों "की-वैल्यू" सिद्धांत पर काम करते हैं, दोनों तेज़ डेटा एक्सेस का वादा करते हैं। लेकिन किसे चुनें?
अगर आपने यह सवाल पूछा है, तो आप अकेले नहीं हैं। Stack Overflow पर "C# में Hashtable की तुलना में Dictionary को क्यों पसंद किया जाता है?" विषय पर हज़ारों व्यूज़ और सैकड़ों वोट हैं। और आज हम इस सवाल का हमेशा के लिए जवाब देंगे। स्पॉयलर: Dictionary लगभग हमेशा जीतता है। लेकिन आइए जानें क्यों।
\n\nइतिहास में एक झलक: Hashtable कहाँ से आया?
\n\nइस मुकाबले को समझने के लिए, C# के इतिहास में झाँकना ज़रूरी है। जब .NET प्लेटफ़ॉर्म पहली बार आया (वर्जन 1.0), डेवलपर्स के पास System.Collections नेमस्पेस से Hashtable क्लास उपलब्ध था। यह एक क्लासिक हैश टेबल थी, जो किसी भी ऑब्जेक्ट को स्टोर कर सकती थी। अच्छा लगता है, है ना? लेकिन एक समस्या थी — टाइपिंग का अभाव।
.NET 2.0 के आगमन और जेनेरिक्स (generics) के साथ, Microsoft ने एक नया कलेक्शन पेश किया — Dictionary<TKey, TValue> जो System.Collections.Generic नेमस्पेस में है। और यहीं से असली जादू शुरू हुआ।
टाइप-सेफ्टी: Dictionary का सबसे बड़ा फायदा
\n\nआइए एक ठोस कोड उदाहरण देखें। Hashtable के साथ काम कैसा दिखता है:
// पुराना तरीका: Hashtable\nHashtable hashtable = new Hashtable();\nhashtable.Add("की1", 123);\nhashtable.Add("की2", "स्ट्रिंग"); // गलती? नहीं, कंपाइल हो जाएगा!\nhashtable.Add(456, "एक और स्ट्रिंग"); // की भी कोई भी ऑब्जेक्ट हो सकता है\n\n// अब डेटा निकालने की कोशिश करते हैं\nint value = (int)hashtable["की2"]; // उफ़! रनटाइम पर InvalidCastException!\n\nसमस्या दिखी? Hashtable किसी भी प्रकार को स्वीकार करता है — की और वैल्यू दोनों के लिए। कंपाइलर कोई भी गलती छोड़ देगा, और आपको इसके बारे में प्रोग्राम चलने पर ही पता चलेगा। यह उन बग्स का सीधा रास्ता है जिन्हें पकड़ना मुश्किल है।
\n\nअब Dictionary देखें:
\n\n// नया, सही तरीका: Dictionary\nDictionary<string, int> dictionary = new Dictionary<string, int>();\ndictionary.Add("की1", 123);\n// dictionary.Add("की2", "स्ट्रिंग"); // कंपाइल एरर! टाइप मैच नहीं करता\n// dictionary.Add(456, "एक और स्ट्रिंग"); // एरर — की string होनी चाहिए\n\n// बिना टाइप कास्टिंग के डेटा निकालें\nint value = dictionary["की1"]; // साफ, सुरक्षित, सुंदर\n\nDictionary टाइप-सेफ है। आप स्पष्ट रूप से बताते हैं कि की और वैल्यू के लिए कौन से टाइप होंगे। कंपाइलर बिल्ड के समय इसकी जाँच करता है। रनटाइम पर कोई अप्रत्याशित अपवाद नहीं — कोड या तो काम करेगा या कंपाइल नहीं होगा।
\n\nप्रदर्शन: कौन तेज़ है?
\n\nदूसरा महत्वपूर्ण पहलू प्रदर्शन है। और यहाँ Dictionary फिर से आगे है। क्यों? इसका कारण है बॉक्सिंग (boxing) और अनबॉक्सिंग (unboxing)।
\n\nजब आप Hashtable के साथ काम करते हैं, तो सभी वैल्यू टाइप (int, double, struct आदि) ऑब्जेक्ट में बॉक्स हो जाते हैं। इससे गार्बेज कलेक्टर पर लोड बढ़ता है और काम धीमा हो जाता है। आइए व्यवहार में जाँच करें:
\n\n// Hashtable: बॉक्सिंग/अनबॉक्सिंग\nHashtable ht = new Hashtable();\nStopwatch sw = Stopwatch.StartNew();\nfor (int i = 0; i < 1000000; i++)\n{\n ht.Add(i, i); // हर int object में बॉक्स होता है\n}\nsw.Stop();\nConsole.WriteLine($"Hashtable जोड़ना: {sw.ElapsedMilliseconds} मि.से.");\n\n// Dictionary: बिना बॉक्सिंग के\nDictionary<int, int> dict = new Dictionary<int, int>();\nsw.Restart();\nfor (int i = 0; i < 1000000; i++)\n{\n dict.Add(i, i); // कोई बॉक्सिंग नहीं — सीधे int के साथ काम\n}\nsw.Stop();\nConsole.WriteLine($"Dictionary जोड़ना: {sw.