D
D
Dmitry Afonchenko2016-03-02 10:40:31
.NET
Dmitry Afonchenko, 2016-03-02 10:40:31

Why does an error occur after trying TryGetValue to add an element with the same key?

Good afternoon, comrades, I have the following code:

private class ThreadsafeMemoizeCache<TArgument, TResult>
        {
            private Dictionary<TArgument, TResult> cache = new Dictionary<TArgument, TResult>();
            
            public TResult GetOrAdd(TArgument key, Func<TArgument, TResult> valueFactory)
            {
                TResult result;
                
                if (cache.TryGetValue(key, out result))
                {
                    return result;
                }
                lock (this)
                {
                    if (!cache.TryGetValue(key, out result))
                    {
                        result = valueFactory(key);
                        Dictionary<TArgument, TResult> newCache = new Dictionary<TArgument, TResult>(cache);
                        newCache.Add(key, result);
                        cache = newCache;
                    }
                }
                return result;
            }
        }

Question of the following kind. For some reason, in this code, an error pops up adding an already existing key. In this case, the same key is added by the same thread. An attempt to modify the code like this also did not work:
lock (this)
                {
                    if (cache.TryGetValue(key, out result))
                    {
                        return result;
                    }

                    if (!cache.TryGetValue(key, out result))
                    {
                        result = valueFactory(key);
                        Dictionary<TArgument, TResult> newCache = new Dictionary<TArgument, TResult>(cache);
                        newCache.Add(key, result);
                        cache = newCache;
                    }
                }

What could be the reason?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
L
Larry Underwood, 2016-03-02
@Indermove

First, I would rewrite the code like this:

private class ThreadsafeMemoizeCache<TArgument, TResult>
    {
      private readonly Dictionary<TArgument, TResult> _internalCache = new Dictionary<TArgument, TResult>();

      private readonly object _internalCacheLocker = new object();

      public TResult GetOrAdd(TArgument key, Func<TArgument, TResult> valueFactory)
      {
        lock (_internalCacheLocker)
        {
          TResult result;
          if (_internalCache.TryGetValue(key, out result))
            return result;

          result = valueFactory(key);
          _internalCache.Add(key, result);
          return result;;
        }
      }
    }

And secondly, I have the following code:
var cache = new ThreadsafeMemoizeCache<string, string>();
cache.GetOrAdd("1", (arg) => string.Empty);
cache.GetOrAdd("1", (arg) => string.Empty);

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question