title: Lock around dictionary access in a WPF application
body: <p>I'm working on an old and large WPF application. The customer reported a bug, which they were able to reproduce, but I can't. There is a class in the application that looks like this:</p>
  <pre class="lang-cs prettyprint-override"><code>public static class PermissionProvider
  {
      private static Dictionary&lt;string, bool&gt; Permissions;
  
      public static void Init()
      {
          Permissions = new Dictionary&lt;string, bool&gt;();
      }
      
      private static object _lock = new object();
      public static bool HasPermission(string permission)
      {
          if (string.IsNullOrEmpty(permission)) return false;
  
          lock (_lock)
          {
              if (Permissions.ContainsKey(permission)) return Permissions[permission];
              var hasPermission = true; // Expensive call a third party module to check user permissions.
              Permissions.Add(permission, hasPermission);
              return hasPermission;
          }
      }
  }
  </code></pre>
  <p>According to the log files provided by the customer, the line <code>Permissions.Add(permission, hasPermission)</code> threw an <code>ArgumentException</code> (key already exists). This doesn't make sense to me; the code checks for the key inside the same lock.</p>
  <p>Based on a test run, all calls to <code>HasPermission</code> seem to be made from the main thread. The program uses <code>Dispatcher.BeginInvoke</code> at places, but my understanding is that locking is not even necessary for that. The dictionary is private and not accessed from anywhere else.</p>
  <p>In what situation could this exception happen?</p>
  <hr />
  <p>My first thought was that the customer was running an old version of the application, but it turns out that this class was only added in the latest one.</p>
  <p>This particular exception should be easy enough to avoid by just changing the <code>Permissions.Add(permission, hasPermission)</code> to <code>Permissions[permission] = hasPermission</code>, but I would prefer to understand why it happened first.</p>