سؤال

أحاول تحديث hashtable في حلقة ولكن الحصول على خطأ:النظام.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;
}

هل هناك طريقة من حوله أو ربما هناك أفضل بنية البيانات لمثل هذا الغرض ؟

هل كانت مفيدة؟

المحلول

وكنت قد قرأت مجموعة من المفاتيح في المثال IEnumerable آخر أولا، ثم foreach على تلك القائمة

        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]);
        }

نصائح أخرى

في مفهوم وأود أن تفعل:

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;
}

إذا كنت تستخدم قاموس بدلا من جدول هاش، وذلك أن هذا النوع من المفاتيح هو معروف فإن أسهل طريقة لجعل نسخة من مجموعة مفاتيح لتجنب هذا الاستثناء هو:

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

لماذا أنت تحصل على استثناء أقول لك أن قمت بتعديل جمع كنت بالتكرار عبر، في حين أن لديك لا؟

وعلى الصعيد الداخلي، وفئة Hashtable ديها حقل الإصدار. إضافة، إدراج، وإزالة طرق الاضافة هذا الإصدار. عند إنشاء العداد على أي من المجموعات التي يعرض جدول هاش، ويشمل الكائن العداد الإصدار الحالي من جدول هاش. الأسلوب MoveNext العداد ليتحقق النسخة العداد ضد لجدول هاش، ولو لم تكن متساوية، فإنه يلقي InvalidOperationException ترونه.

وهذه هي آلية بسيطة جدا لتحديد ما إذا كان جدول هاش تم تعديله. في الواقع انها قليلا بسيطة جدا. جمع مفاتيح يجب حقا للحفاظ على نسختها الخاصة، ويجب الأسلوب GetEnumerator لحفظ نسخة جمع في العداد، وليس نسخة من جدول هاش ل.

وهناك آخر، أكثر دهاء عيب تصميم في هذا النهج. النسخة هو Int32. طريقة UpdateVersion ليس له حدود فحص. ولذلك فمن الممكن، إذا قمت بإجراء بالضبط العدد الصحيح من تعديلات على جدول هاش (2 مرات Int32.MaxValue، يعطي أو يأخذ)، للحصول على الإصدار على جدول هاش والعداد أن تكون هي نفسها حتى ولو كنت قد غيرت جذريا في جدول هاش منذ خلق العداد. وبالتالي فإن طريقة MOVENEXT لا رمي استثناء على الرغم من أنه ينبغي، وستحصل على نتائج غير متوقعة.

أبسط طريقة هي نسخ المفاتيح في مجموعة منفصلة ، ثم أعاد من خلال هذا بدلا من ذلك.

هل تستخدم .NET framework 3.5?إذا كان الأمر كذلك ، LINQ يجعل الأمور أسهل قليلا.

الجزء الرئيسي هو ToArray() طريقة

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

ولا يمكنك تغيير مجموعة من العناصر المخزنة في مجموعة بينما كنت تعداد أكثر من ذلك، لأن ذلك يجعل الحياة صعبة للغاية بالنسبة للمكرر في معظم الحالات. النظر في القضية حيث يمثل جمع شجرة متوازنة، ويمكن أن تخضع أيضا تناوب بعد إدراج. ان اعدد لها أي وسيلة معقولة لمتابعة ما ينظر إليه.

ولكن، إذا كنت مجرد محاولة لتحديث القيمة ثم يمكنك كتابة:

deEntry.Value = sValue

وتحديث قيمة هنا ليس له أي تأثير على العداد.

وهذه هي الطريقة التي فعلت ذلك ضمن القاموس. يعيد كل قيمة في ديكت إلى false:

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;
}

والامر يعتمد على ماذا كنت حلقات عبر العناصر في جدول هاش. ولكن هل من المحتمل أن تكون قادرة على تكرار الفكر مفاتيح بدلا من ذلك. لذلك

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

والخيار الآخر هو إنشاء جدول هاش جديد. تكرار خلال أول مع إضافة عناصر إلى الثانية ثم استبدال الأصلي مع واحدة جديدة.
حلقات من خلال مفاتيح يتطلب أقل مخصصات الكائن بالرغم من ذلك.

List<string> keyList = htSettings_m.Keys.Cast<string>().ToList();
foreach (string key in keyList) {

وهذا هو نفس إجابات أخرى، ولكن أنا أحب سطر واحد للحصول على المفاتيح.

وتحويله إلى صفيف:

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;
}
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;    
}

وربما يمكنك استخدام مجموعة Hashtable.Keys؟ تعداد من خلال ذلك قد يكون من الممكن أثناء تغيير جدول هاش. ولكن هذا فقط تخمين ...

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top