What to add for the update portion in ConcurrentDictionary AddOrUpdate

C#Concurrent Collections

C# Problem Overview


I am trying to re-write some code using Dictionary to use ConcurrentDictionary. I have reviewed some examples but I am still having trouble implementing the AddOrUpdate function. This is the original code:

    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;

I don't know what to add for the update portion:

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

Any pointers would be appreciated.

C# Solutions


Solution 1 - C#

You need to pass a Func which returns the value to be stored in the dictionary in case of an update. I guess in your case (since you don't distinguish between add and update) this would be:

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

I.e. the Func always returns the sessionId, so that both Add and Update set the same value.

BTW: there is a sample on the MSDN page.

Solution 2 - C#

I hope, that I did not miss anything in your question, but why not just like this? It is easier, atomic and thread-safe (see below).

userDic[authUser.UserId] = sessionId;

> Store a key/value pair into the dictionary unconditionally, overwriting any value for that key if the key already exists: Use the indexer’s setter

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

The indexer is atomic, too. If you pass a function instead, it might not be:

> All of these operations are atomic and are thread-safe with regards to all other operations on the ConcurrentDictionary. The only caveat to the atomicity of each operation is for those which accept a delegate, namely AddOrUpdate and GetOrAdd. [...] these delegates are invoked outside of the locks

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

Solution 3 - C#

I ended up implementing an extension method:

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

Solution 4 - C#

For those who are interested in, I am currently implementing a case which is a great example for using the "oldValue" aka existing value instead of forcing a new one (personally I don't like the term "oldValue" as it is not that old when it was created just a few processor ticks ago from within a parallel thread).

dictionaryCacheQueues.AddOrUpdate(
    uid,
    new ConcurrentQueue<T>(),
    (existingUid, existingValue) => existingValue
);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser438331View Question on Stackoverflow
Solution 1 - C#M4NView Answer on Stackoverflow
Solution 2 - C#Niklas PeterView Answer on Stackoverflow
Solution 3 - C#steve cookView Answer on Stackoverflow
Solution 4 - C#NicolasView Answer on Stackoverflow