[C#] How to modify a Hashtable entry value in-place?!

Vovka
Уже с Приветом
Posts: 1906
Joined: 14 Mar 2001 10:01

[C#] How to modify a Hashtable entry value in-place?!

Post by Vovka »

Вроде простейшая проблема, но что-то я ничего не понимаю. Можно, конечно, удалить и вставить новое, но это очень криво. Сначала попробовал так:

Code: Select all

Hashtable map = new Hashtable();

map["first"] = 10;
map["second"] = 20;

foreach(DictionaryEntry e in map)
{
   e.Value = 100;
   Console.WriteLine("{0}: {1}", key, map[key]);
}


Вообще не компилит, причём выдаёт совершенно невразумительное сообщение об ошибке.

Вот так вот тоже не работает:

Code: Select all

Hashtable map = new Hashtable();

map["first"] = 10;
map["second"] = 20;

foreach(object key in map.Keys)
{
   map[key] = 100;
   Console.WriteLine("{0}: {1}", key, map[key]);
}

Бросает исключение, что коллекция была изменена и она не может дальше енумерэйтить.

Так я же не ключи меняю?!
blanko27
Уже с Приветом
Posts: 2264
Joined: 17 Jun 2003 04:41
Location: Just like US

Re: [C#] How to modify a Hashtable entry value in-place?!

Post by blanko27 »

Vovka wrote:Бросает исключение, что коллекция была изменена и она не может дальше енумерэйтить.
Так я же не ключи меняю?!
Ну правильно, запрещается изменять коллекцию во время енумерации. Это будет работать:

Code: Select all

map["first"] = 100; 
map["second"] = 100;

foreach(DictionaryEntry e in map)
{
    Console.WriteLine("{0}: {1}", e.Key, map[e.Key]);
}
...а мы такой компанией, возьмем, да и припремся к Элис!
Vovka
Уже с Приветом
Posts: 1906
Joined: 14 Mar 2001 10:01

Re: [C#] How to modify a Hashtable entry value in-place?!

Post by Vovka »

blanko27 wrote: Ну правильно, запрещается изменять коллекцию во время енумерации.

Интересно, какая светлая голова это придумала и почему.

blanko27 wrote:Это будет работать:

Code: Select all

map["first"] = 100; 
map["second"] = 100;

foreach(DictionaryEntry e in map)
{
    Console.WriteLine("{0}: {1}", e.Key, map[e.Key]);
}


Так здесь вы ничего не меняете!
Или вы демонстрируете, что я могу читать элементы во время енумерации? Ну слава богу, хоть это можно. :mrgreen:
Palych
Уже с Приветом
Posts: 13683
Joined: 16 Jan 2001 10:01

Post by Palych »

Vot ona - prichina pochemu nel'zya Itaretors pryatat' za fancy operators!

A ved' oni eto govno i v Java taschat... :х
blanko27
Уже с Приветом
Posts: 2264
Joined: 17 Jun 2003 04:41
Location: Just like US

Post by blanko27 »

Можно применить такую последовательность:

Code: Select all

         Hashtable map = new Hashtable(); 

         map["first"] = 10;
         map["second"] = 20;

         ArrayList items = new ArrayList();
         foreach (string key in map.Keys)
         {
            items.Add(key);
         }

         foreach(string key in items)
         {
            map[key] = 100;
            Console.WriteLine("{0}: {1}", key, map[key]);
         }
...а мы такой компанией, возьмем, да и припремся к Элис!
User avatar
Strannik223
Уже с Приветом
Posts: 569
Joined: 14 Dec 2003 04:06
Location: Львов->Киев->Торонто

Post by Strannik223 »

Странно, но за 2 года програмирования на шарпе не наступал на эту особенность.
А зачем вам модифицировать все элементы в hashtable?
Никакой разрухи нет. (с) Проф. Преображенский.
blanko27
Уже с Приветом
Posts: 2264
Joined: 17 Jun 2003 04:41
Location: Just like US

Post by blanko27 »

Strannik223 wrote:...А зачем вам модифицировать все элементы в hashtable?
Он, по-видимому, упростил ситуацию для наглядности. Ему не надо модофоцировать все, а только некоторые, подпадающие под определенное условие. Это тоже невозможно при энумерации.
...а мы такой компанией, возьмем, да и припремся к Элис!
Bobo
Уже с Приветом
Posts: 518
Joined: 04 Jun 2002 01:40
Location: CA, USA

Post by Bobo »

Ну надо еще понимать, что такое mutable и immutable.

Вот так будет работать:

Code: Select all

class Q
{
  public Q(int x){X=x;}
  public int X;
}

void Main()
{
  Hashtable t = new Hashtable()
  t.Add("a", new Q(20))
  t.Add("b", new Q(30))
  foreach (object key in t.Keys)
    ((Q)t[key]).X = 100;
}


А вот если сделать так:

Code: Select all

Arraylist a = new Arraylist();
a.Add(10);
a.Add(20);
foreach (object o in a)
  o = 100;


то ошибки не будет, но и значения, естественно не поменяются.
blanko27
Уже с Приветом
Posts: 2264
Joined: 17 Jun 2003 04:41
Location: Just like US

Post by blanko27 »

Bobo wrote:Вот так будет работать:

Code: Select all

class Q
{
  public Q(int x){X=x;}
  public int X;
}
... ...
}
Да это решение с классом очень хорошее. Но одна существующая проблма этого решения, что оно не позволяет добавлять и удалять элементы из коллекции по необходимому условию, типа:

Code: Select all

foreach (object key in t.Keys)
{
    t.Remove(key);
}
...а мы такой компанией, возьмем, да и припремся к Элис!
Bobo
Уже с Приветом
Posts: 518
Joined: 04 Jun 2002 01:40
Location: CA, USA

Post by Bobo »

blanko27 wrote:Но одна существующая проблма этого решения,...


Естественно, итератор по определению запрешает изменять коллекцию.
Я просто хотел обратить внимание на то, что надо различать случаи, когда нам надо менять коллекцию, а когда - ее елементы.
Vovka
Уже с Приветом
Posts: 1906
Joined: 14 Mar 2001 10:01

Post by Vovka »

Bobo wrote:Ну надо еще понимать, что такое mutable и immutable.

И что это такое? 8O
В Language Reference такого понятия не нашёл.

Ваше решение, возможно, работает, но это чистейшей воды workaround (я бы даже назвал hack).

Никакой мало-мальски убедительной причины для того, чтобы не позволять в таких случая менять Value я по-прежнему не вижу. Скорее всего, это design bug.
leprechaun
Удален за рекламу собственного бизнеса
Posts: 178
Joined: 24 Jul 2002 08:02
Location: Baile Atha Cliath

Post by leprechaun »

Vovka wrote:
Bobo wrote:Ну надо еще понимать, что такое mutable и immutable.

И что это такое? 8O
В Language Reference такого понятия не нашёл.


Google would be definitely helpful here. Some of the links that came first:

http://www.javaworld.com/javaworld/java ... table.html
http://www.rh.edu/~kousek/cish4020/ppt/Chapter15.ppt
http://www.cs.man.ac.uk/arch/people/j-s ... ode30.html
User avatar
Strannik223
Уже с Приветом
Posts: 569
Joined: 14 Dec 2003 04:06
Location: Львов->Киев->Торонто

Post by Strannik223 »

Vovka wrote:Никакой мало-мальски убедительной причины для того, чтобы не позволять в таких случая менять Value я по-прежнему не вижу. Скорее всего, это design bug.


Согласен.
Я понимаю почему нельзя менять Key, но Value за что под раздачу попало непонятно.
Никакой разрухи нет. (с) Проф. Преображенский.
Bobo
Уже с Приветом
Posts: 518
Joined: 04 Jun 2002 01:40
Location: CA, USA

Post by Bobo »

Vovka wrote:
Bobo wrote:Ну надо еще понимать, что такое mutable и immutable.

И что это такое? 8O
В Language Reference такого понятия не нашёл.


В C# Language Reference ети понятия упоминаются только в связи с типом string. (который reference but immutable)
А разьяснения про отличия value types ot reference types разжеваны повсеместно.

Ваше решение, возможно, работает, но это чистейшей воды workaround (я бы даже назвал hack).

ето чистой воды демонстрация того, что в вашем случае проблема не с итератором, а с тем, что значение value type поменять в принципе невозможно. Его можно только заменить на новый обьеkт.

Никакой мало-мальски убедительной причины для того, чтобы не позволять в таких случая менять Value я по-прежнему не вижу.

Я надеюсь, причину не позволять менять коллекцию вы видите. А в случае с immutable types изменение value - ето вставка нового обьекта.
Sam Adams
Уже с Приветом
Posts: 1316
Joined: 03 Jul 2003 06:02
Location: USA

Re: [C#] How to modify a Hashtable entry value in-place?!

Post by Sam Adams »

Vovka wrote:

Code: Select all

foreach(object key in map.Keys)
{
   map[key] = 100;
   Console.WriteLine("{0}: {1}", key, map[key]);
}

Бросает исключение, что коллекция была изменена и она не может дальше енумерэйтить.


Похоже, что разработчики немного недаработали этот момент. Я в похожих случаях (если производительность не критична) делаю так -

Code: Select all

public static IList CreateList(IEnumerator ie);   // для использования итератора в конструкции foreach

foreach (object key in CreateList(map.Keys.GetEnumerator()))
{
   map[key] = 100;
}

Return to “Вопросы и новости IT”