Что добавить для части обновления в ConcurrentDictionary AddOrUpdate - PullRequest
95 голосов
/ 11 августа 2011

Я пытаюсь переписать некоторый код, используя словарь для использования ConcurrentDictionary.Я рассмотрел несколько примеров, но у меня все еще возникают проблемы с реализацией функции AddOrUpdate.Это оригинальный код:

    dynamic a = HttpContext;
    Dictionary<int, string> userDic = this.HttpContext.Application["UserSessionList"] as Dictionary<int, String>;

   if (userDic != null)
   {
      if (useDic.ContainsKey(authUser.UserId))
      {
        userDic.Remove(authUser.UserId);
      }
   }
  else
  {
     userDic = new Dictionary<int,string>();
  }
  userDic.Add(authUser.UserId, a.Session.SessionID.ToString());
  this.HttpContext.Application["UserDic"] = userDic;

Я не знаю, что добавить для части обновления:

userDic.AddOrUpdate(authUser.UserId,
                    a.Session.SessionID.ToString(),
                    /*** what to add here? ***/);

Любые указатели будут оценены.

Ответы [ 4 ]

201 голосов
/ 11 августа 2011

Вам необходимо передать Func, который возвращает значение, которое будет сохранено в словаре в случае обновления.Я предполагаю, что в вашем случае (так как вы не различаете add и update) это будет:

var sessionId = a.Session.SessionID.ToString();
userDic.AddOrUpdate(
  authUser.UserId,
  sessionId,
  (key, oldValue) => sessionId);

Т.е. Func всегда возвращает sessionId, так что и Add, и Update устанавливают одно и то же значение.

Кстати: есть образец на странице MSDN .

55 голосов
/ 26 сентября 2015

Надеюсь, я ничего не пропустил в вашем вопросе, но почему бы просто так? Это проще, атомарнее и поточнее (см. Ниже).

userDic[authUser.UserId] = sessionId;

Сохраните пару ключ / значение в словаре безоговорочно, перезаписывая любое значение для этого ключа, если ключ уже существует: используйте установщик индексатора

(см .: http://blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx)

Индексатор тоже атомарный. Если вместо этого вы передадите функцию, это может быть не так:

Все эти операции являются атомарными и поточно-ориентированными по отношению ко всем другим операциям в ConcurrentDictionary. Единственное предостережение к атомарности каждой операции - для тех, которые принимают делегата, а именно AddOrUpdate и GetOrAdd. [...] эти делегаты вызываются за пределы замков

См .: http://blogs.msdn.com/b/pfxteam/archive/2010/01/08/9945809.aspx

26 голосов
/ 09 марта 2014

В итоге я реализовал метод расширения:

static class ExtensionMethods
{
    // Either Add or overwrite
    public static void AddOrUpdate<K, V>(this ConcurrentDictionary<K, V> dictionary, K key, V value)
    {
        dictionary.AddOrUpdate(key, value, (oldkey, oldvalue) => value);
    }
}
1 голос
/ 28 марта 2014

Для тех, кто интересуется, я в настоящее время реализую случай, который является отличным примером для использования «oldValue» или существующего значения вместо принудительного ввода нового (лично мне не нравится термин «oldValue», так как не так уж и стар, когда он был создан всего несколькими тактами назад из параллельного потока).

dictionaryCacheQueues.AddOrUpdate(
    uid,
    new ConcurrentQueue<T>(),
    (existingUid, existingValue) => existingValue
);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...