ConcurrentDictionary AddOrUpdate
Я пытаюсь переписать код с помощью словаря для использования 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? ***/);
Любые указатели будут оценены.
Ответы
Ответ 1
Вам нужно передать Func
, который возвращает значение, которое будет храниться в словаре в случае обновления. Я думаю, в вашем случае (поскольку вы не различаете добавление и обновление) это будет:
var sessionId = a.Session.SessionID.ToString();
userDic.AddOrUpdate(
authUser.UserId,
sessionId,
(key, oldValue) => sessionId);
т.е. Func
всегда возвращает sessionId, так что и Add, и Update устанавливают одно и то же значение.
BTW: есть образец на странице MSDN.
Ответ 2
Я надеюсь, что я ничего не пропустил в вашем вопросе, но почему бы не просто так? Это проще, атомно и поточно-безопасно (см. Ниже).
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
Ответ 3
В результате я использовал метод расширения:
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);
}
}
Ответ 4
Для тех, кто заинтересован в этом, я в настоящее время реализую случай, который является отличным примером использования "oldValue" как существующего значения вместо того, чтобы форсировать новый (лично мне не нравится термин "oldValue", поскольку он не так уж и старый, когда он был создан всего лишь несколько процессоров тиков назад изнутри параллельного потока).
dictionaryCacheQueues.AddOrUpdate(
uid,
new ConcurrentQueue<T>(),
(existingUid, existingValue) => existingValue
);