C# System.Collections.Generic.Dictionary`2.Insert - An item with the same key has already been added
<p><em>This question is in regards to a .Net Framework 4.5 MVC Web Application.</em></p>

<p>I've got a block of code that we've inherited and been using for years that generically converts a DataTable to a List&lt;T&gt;, and one of the private methods gets a list of the properties for a generic class, for example:</p>

<p><strong>ORIGINAL CODE</strong></p>

<pre><code>    private static Dictionary&lt;Type, IList&lt;PropertyInfo&gt;&gt; typeDictionary = new Dictionary&lt;Type, IList&lt;PropertyInfo&gt;&gt;();

    public static IList&lt;PropertyInfo&gt; GetPropertiesForType&lt;T&gt;()
    {
        //variables
        var type = typeof(T);

        //get types
        if (!typeDictionary.ContainsKey(typeof(T)))
        {
            typeDictionary.Add(type, type.GetProperties().ToList());
        }

        //return
        return typeDictionary[type];
    }
</code></pre>

<p><br />
Nothing incredibly exciting going on there, it's just making sure the typeDictionary doesn't already contain the key (type) and adds it to the dictionary (key=type, value=properties), so we can access them later.</p>

<p>We use this code generically for any kind of "model" object, but for this particular example, this is the one that's given me trouble on 2 different occasions.</p>

<p><strong>MODEL OBJECT</strong></p>

<pre><code>public class GetApprovalsByUserId
{
    // constructor
    public GetApprovalsByUserId()
    {
        TicketId = 0;
        ModuleName = string.Empty;
        ModuleIcon = string.Empty;
        ApprovalType = string.Empty;
        VIN = string.Empty;
        StockNumber = string.Empty;
        Year = 0;
        Make = string.Empty;
        Model = string.Empty;
        Services = string.Empty;
        RequestedDate = DateTime.MinValue;
    }

    // public properties
    public int TicketId { get; set; }
    public string ModuleName { get; set; }
    public string ModuleIcon { get; set; }
    public string ApprovalType { get; set; }
    public string VIN { get; set; }
    public string StockNumber { get; set; }
    public int Year { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }
    public string Services { get; set; }
    public DateTime RequestedDate { get; set; }
}
</code></pre>

<p><br />
Again, nothing really significant going on in that particular model class, and nothing any different than we use in any other class.</p>

<p>Like I said, we use this code generically in several projects, and have never once had issues with it, but on 2 separate occasions in the past day we've had it throw the following exception:</p>

<p><strong>An item with the same key has already been added.</strong></p>

<pre><code>at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource)
at System.Collections.Generic.Dictionary`2.Insert(TKey key, TValue value, Boolean add)
at Utilities.Extensions.GetPropertiesForType[T]()
at Utilities.Extensions.ToObject[T](DataRow row)
at Utilities.Extensions.ToList[T](DataTable table)
</code></pre>

<p><br />
In case it is helpful, you can see the full Extensions.cs class (static) that the extension methods live in here:</p>

<p><a href="https://pavey.azurewebsites.net/resources/Extensions.txt" rel="nofollow">https://pavey.azurewebsites.net/resources/Extensions.txt</a></p>

<p>My questions are:</p>

<ol>
<li><p>Given the fact that the code is already doing a <em>!typeDictionary.ContainsKey(typeof(T))</em> check, how is it possible that it could ever pass that test, yet fail on the <em>typeDictionary.Add(type, type.GetProperties().ToList());</em> call?</p></li>
<li><p>Why would it be so sporadic? It seemingly works 99% of the time, using the same code, the same class (GetApprovalsByUserId, shown above), and never has failed otherwise in any other project or any other model class.</p></li>
</ol>

<p>We have <strong>not</strong> been able to reproduce this issue using the exact same code, model, data, or otherwise the exact same setup in any environment, so not sure how to safe-guard this code anymore than it already is.</p>

<p>One thought I have is to change the code to this:</p>

<p><strong>PROPOSED CODE CHANGE</strong></p>

<pre><code>    private static Dictionary&lt;Type, IList&lt;PropertyInfo&gt;&gt; typeDictionary = new Dictionary&lt;Type, IList&lt;PropertyInfo&gt;&gt;();

    public static IList&lt;PropertyInfo&gt; GetPropertiesForType&lt;T&gt;()
    {
        //variables
        var type = typeof(T);
        IList&lt;PropertyInfo&gt; properties = null;

        //get types
        try
        {
            if (!typeDictionary.ContainsKey(type))
            {
                typeDictionary.Add(type, type.GetProperties().ToList());
            }
        }
        catch
        {
        }

        // try get value
        typeDictionary.TryGetValue(type, out properties);

        // return
        return properties;
    }
</code></pre>

<p><br />
But since I can't reproduce the error in the first place, I'm not entire sure if this is bullet proof either. My thinking would be that it's just something weird with ContainsKey, particularly with using a typeof(T) as the "key", which allows it to pass the test in odd cases, when it really shouldn't, but the <strong>Add</strong> fails because it knows the key is already there. So if I try/catch it, if the ContainsKey incorrectly tells me it's not there, when it in fact is, the Add will still fail, but I'll catch it, and move on, and then I can TryParse to get the value out, and all should be well.</p>

<p>Appreciate any thoughts, ideas, or specifically how to reproduce the problem with the <strong>Original Code</strong> shown above, and recommended improvements to safe guard it.</p>