Словарь .NET: потенциальные проблемы параллелизма? - PullRequest
8 голосов
/ 29 января 2009

Я работаю над обслуживанием проекта .NET, и у меня возникли некоторые проблемы, с которыми я с удовольствием поделюсь с вами, ребята =)

Код проблемы:

if( evilDict.Count < 1 )
{
    foreach (Item item in GetAnotherDict())
        if (!evilDict.containsKey(item.name.ToLower().Trim()))
            evilDict.add(item.name.ToLower().Trim(), item.ID);
}

Несмотря на проверку contains (), я получаю ArgumentException, сообщающий, что элемент с таким же ключом уже добавлен. Мы только столкнулись с этой проблемой на производстве, а не на тестировании, что заставляет меня заподозрить проблему параллелизма. Что мне интересно, так это:

  • Как вы думаете, это проблема параллелизма?
  • Как мне это исправить?
  • Является ли мое исправление жизнеспособным (см. Ниже)?
  • Это мой первый удар в .NET, словари, как правило, являются источником проблем?

Вот мое потенциальное исправление, заменив функцию dictionary.add ()

protected static void DictAddHelper(Dictionary<String, int> dict, String key, int value)
{
    lock (dict)
    {
        key = key.ToLower().Trim();
        if (dict.ContainsKey(key) == false)
        {
            try
            {
                dict.Add(key, value);
            }
            catch (ArgumentException aex)
            {
                StringBuilder debugInfo = new StringBuilder();
                debugInfo.AppendLine("An argumentException has occured: " + aex.Message);
                debugInfo.AppendLine("key = " + key);
                debugInfo.AppendLine("value = " + value);
                debugInfo.AppendLine("---Dictionary contains---");

                foreach (String k in dict.Keys)
                    debugInfo.AppendLine(k + " = " + dict[k]);

                log.Error(debugInfo, aex);
            }
        }
    }
}

EDIT:

Предложения, которые не требуют от меня создания поточно-ориентированной реализации класса Dict, лучше, так как это будет довольно большой рефакторинг, который не будет очень желанным предложением =)

EDIT2:

Я пытался

lock (((IDictionary)dict).SyncRoot)

Но я получаю

Error   28  Using the generic type 'System.Collections.Generic.IDictionary<TKey,TValue>' requires '2' type arguments    

Тогда я попробую это:

lock (((IDictionary<String, int>)dict).SyncRoot)

Ошибка:

Error   28  'System.Collections.Generic.IDictionary<string,int>' does not contain a definition for 'SyncRoot'

ЗАКЛЮЧИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ (наверное):

Спасибо за все ответы!

Теперь все, что я хочу знать, это. Мой метод (DictAddHelper) будет работать вообще, и если нет, то почему?

Ответы [ 11 ]

0 голосов
/ 17 января 2011

рефакторинг не должен быть болезненным или сложным для выполнения. Просто выполните следующие рефакторинги:

1) создайте класс контейнера-обертки для вашего словаря, который реализует тот же интерфейс, что и словарь

2) найдите объявление в вашем словаре и примените рефакторинг, изменив объявленный тип (на тот, который вы только что создали)

3) попробуйте собрать в это время, если ваша оболочка реализует все элементы интерфейса, вы не должны получать никаких ошибок компиляции

4) на средствах доступа к вашему словарю оберните все в блокировку или любую другую стратегию синхронизации, которую вы хотите применить

...