2008-11-28 16 views
9

मैं एक लूप में हैशटेबल को अपडेट करने की कोशिश कर रहा हूं लेकिन एक त्रुटि प्राप्त कर रहा हूं: System.InvalidOperationException: संग्रह संशोधित किया गया था; गणना ऑपरेशन निष्पादित नहीं हो सकता है।एक लूप में सी # हैशटेबल को कैसे अपडेट करें?

private Hashtable htSettings_m = new Hashtable(); 
htSettings_m.Add("SizeWidth", "728"); 
htSettings_m.Add("SizeHeight", "450"); 
string sKey = ""; 
string sValue = ""; 
foreach (DictionaryEntry deEntry in htSettings_m) 
{ 
    // Get value from Registry and assign to sValue. 
    // ... 
    // Change value in hashtable. 
    sKey = deEntry.Key.ToString(); 
    htSettings_m[sKey] = sValue; 
} 

क्या इसके आसपास कोई रास्ता है या शायद इस उद्देश्य के लिए बेहतर डेटा संरचना है?

+0

मानते हैं कि यह एक dup प्रश्न देखें है कि: http://stackoverflow.com/questions/287195/how-to-add-items-to-a-collection जबकि-उपभोग करने वाला यह –

उत्तर

14

यदि आप किसी अन्य IEnumerable उदाहरण में चाबियों का संग्रह पढ़ सकता है पहले, तो उस सूची

 System.Collections.Hashtable ht = new System.Collections.Hashtable(); 

     ht.Add("test1", "test2"); 
     ht.Add("test3", "test4"); 

     List<string> keys = new List<string>(); 
     foreach (System.Collections.DictionaryEntry de in ht) 
      keys.Add(de.Key.ToString()); 

     foreach(string key in keys) 
     { 
      ht[key] = DateTime.Now; 
      Console.WriteLine(ht[key]); 
     } 
+0

यह एक करेगा। धन्यवाद! –

1

आप संग्रह में संग्रहीत वस्तुओं का सेट नहीं बदल सकते हैं, जबकि आप इसके बारे में बता रहे हैं, क्योंकि इससे ज्यादातर मामलों में इटेटरेटर के लिए जीवन बहुत मुश्किल हो जाता है। उस मामले पर विचार करें जहां संग्रह एक संतुलित पेड़ का प्रतिनिधित्व करता है, और एक डालने के बाद घूर्णन से गुजर सकता है। गणना के पास जो कुछ देखा है उसका ट्रैक रखने का कोई व्यावहारिक तरीका नहीं होगा।

हालांकि, अगर आप सिर्फ मान अपडेट कोशिश कर रहे हैं तो आप लिख सकते हैं:

deEntry.Value = sValue 

मूल्य अपडेट कर रहा है यहाँ प्रगणक पर कोई प्रभाव नहीं है।

+1

संकलित नहीं करता है: 'डेन्ट्री' के सदस्यों को संशोधित नहीं कर सकता क्योंकि यह 'foreach iteration variable' –

+1

है, यह – swordfish

4

अवधारणा में मैं करना होगा:

Hashtable table = new Hashtable(); // ps, I would prefer the generic dictionary.. 
Hashtable updates = new Hashtable(); 

foreach (DictionaryEntry entry in table) 
{ 
    // logic if something needs to change or nog 
    if (needsUpdate) 
    { 
     updates.Add(key, newValue); 
    } 
} 

// now do the actual update 
foreach (DictionaryEntry upd in updates) 
{ 
    table[upd.Key] = upd.Value; 
} 
+0

अच्छा समाधान भी काम नहीं करेगा। धन्यवाद। –

-4

शायद तुम Hashtable.Keys संग्रह का उपयोग कर सकते हैं? हैशटेबल को बदलते समय इसके माध्यम से गणना संभव हो सकती है। लेकिन यह केवल एक अनुमान है ...

+0

नहीं, यह काम नहीं करता है। –

-1
private Hashtable htSettings_m = new Hashtable(); 

htSettings_m.Add("SizeWidth", "728");  
htSettings_m.Add("SizeHeight", "450");  
string sValue = "";  
foreach (string sKey in htSettings_m.Keys)  
{  
    // Get value from Registry and assign to sValue  
    // ...  
    // Change value in hashtable.  
    htSettings_m[sKey] = sValue;  
} 
+0

एक ही त्रुटि उत्पन्न करता है। –

+0

पहली बार परीक्षण किए बिना दोषपूर्ण स्मृति से प्रतिक्रिया देने में समस्या है। मैंने इस बारे में फिर से सोचा और मुझे याद आया कि हैशटेबल एक हैशटेबल के लिए एक ही एन्यूमरेटर प्रकार का उपयोग करता है और इसकी कुंजी के लिए। मेरी राय में एक गंभीर रूप से दोषपूर्ण कार्यान्वयन। –

+0

नहीं, समस्या गणनाकर्ता प्रकार नहीं है - यह है कि कुंजी गुण सभी चाबियों की * प्रतिलिपि * नहीं लेता है, यह केवल अंतर्निहित संग्रह पर पुनरावृत्त करता है। जब आपको प्रतिलिपि लेने की आवश्यकता होती है, तो स्पष्ट रूप से ऐसा करें। यह वही व्यवहार है जो मैं चाहता हूं और व्यक्तिगत रूप से उम्मीद करता हूं। –

0

यह कारण है कि आप आइटम के माध्यम से पाशन कर रहे हैं पर निर्भर करता है से अधिक foreach हैशटेबल में। लेकिन आप शायद इसके बजाय चाबियों को फिर से भरने में सक्षम होंगे। तो

foreach (String sKey in htSettings_m.Keys) 
{ // Get value from Registry and assign to sValue. 
    // ...  
    // Change value in hashtable. 
    htSettings_m[sKey] = sValue; 
} 

दूसरा विकल्प एक नया हैशटेबल बनाना है। दूसरी बार वस्तुओं को जोड़ने के दौरान पहली बार इटरेट करें, फिर मूल को नए से बदलें।
कुंजी के माध्यम से लूपिंग हालांकि कम ऑब्जेक्ट आवंटन की आवश्यकता है।

2

चाबियों को एक अलग संग्रह में कॉपी करने का सबसे आसान तरीका है, फिर इसके बजाए फिर से शुरू करें।

क्या आप .NET 3.5 का उपयोग कर रहे हैं? यदि ऐसा है, तो LINQ चीजों को थोड़ा आसान बनाता है।

3

आप एक Hashtable के बजाय एक शब्दकोश का उपयोग कर रहे हैं, तो इतना है कि कुंजी के प्रकार में जाना जाता है, सबसे आसान तरीका यह अपवाद से बचने के लिए कुंजी संग्रह की एक प्रतिलिपि बनाने के लिए है:

foreach (string key in new List<string>(dictionary.Keys)) 

आपको अपवाद क्यों मिल रहा है कि आपने उस संग्रह को संशोधित किया है जिस पर आप पुनरावृत्ति कर रहे हैं, वास्तव में जब आपने नहीं किया है?

आंतरिक रूप से, हैशटेबल वर्ग में संस्करण फ़ील्ड है। जोड़ें, सम्मिलित करें, और निकालें विधियों को इस संस्करण में वृद्धि। जब आप हैशटेबल के किसी भी संग्रह पर एक गणनाकर्ता बनाते हैं, तो गणनाकर्ता ऑब्जेक्ट में हैशटेबल का वर्तमान संस्करण शामिल होता है। गणनाकर्ता की MoveNext विधि हैशटेबल के विरुद्ध गणक के संस्करण की जांच करती है, और यदि वे बराबर नहीं हैं, तो यह आपके द्वारा देखे जा रहे अमान्यऑपरेशन अपवाद को फेंकता है।

यह निर्धारित करने के लिए है कि हैशटेबल को संशोधित किया गया है या नहीं, यह एक बहुत ही सरल तंत्र है। वास्तव में यह थोड़ा बहुत आसान है। कुंजी संग्रह को वास्तव में अपने संस्करण को बनाए रखना चाहिए, और इसकी GetEnumerator विधि को संग्रह के संस्करण को गणनाकर्ता को सहेजना चाहिए, हैशटेबल के संस्करण नहीं।

इस दृष्टिकोण में एक और, subtler डिजाइन दोष है। संस्करण एक इंट 32 है। UpdateVersion विधि कोई सीमा जांच नहीं करता है। इसलिए यह संभव है, यदि आप हैशटेबल के संस्करण के लिए हैशटेबल (2 बार Int32.MaxValue, दे या ले लें) में संशोधन की सही संख्या बनाते हैं, तो गणना करने के बाद से आप मूल रूप से हैशटेबल को बदल चुके हैं गणक तो MoveNext विधि अपवाद को फेंक नहीं देगा, भले ही इसे चाहिए, और आपको अप्रत्याशित परिणाम मिलेंगे।

2

महत्वपूर्ण हिस्सा

var dictionary = new Dictionary<string, string>(); 
foreach(var key in dictionary.Keys.ToArray()) 
{ 
    dictionary[key] = "new value"; 
} 
+0

बहुत आसान समाधान। – Lars

0

यह मैं इसे कैसे एक शब्दकोश के भीतर किया है toArray() विधि है; गलत पर dict में हर मूल्य रीसेट करता है:

Dictionary<string,bool> dict = new Dictionary<string,bool>(); 

for (int i = 0; i < dict.Count; i++) 
{ 
    string key = dict.ElementAt(i).Key; 
    dict[key] = false; 
} 
0
List<string> keyList = htSettings_m.Keys.Cast<string>().ToList(); 
foreach (string key in keyList) { 

यह अन्य उत्तर के रूप में ही है, लेकिन मैं कुंजी प्राप्त करने के लिए एक लाइन की तरह।

+1

स्वीकार्य उत्तर पर एक टिप्पणी के रूप में यह बेहतर होगा। –

0

एक सरणी के लिए यह कन्वर्ट:

private Hashtable htSettings_m = new Hashtable(); 
htSettings_m.Add("SizeWidth", "728"); 
htSettings_m.Add("SizeHeight", "450"); 
string sKey = ""; 
string sValue = ""; 

ArrayList htSettings_ary = new ArrayList(htSettings_m.Keys) 
foreach (DictionaryEntry deEntry in htSettings_ary) 
{ 
    // Get value from Registry and assign to sValue. 
    // ... 
    // Change value in hashtable. 
    sKey = deEntry.Key.ToString(); 
    htSettings_m[sKey] = sValue; 
} 
संबंधित मुद्दे