字典抛出参数异常,即使受ContainsKey保护

本文关键字:ContainsKey 保护 参数 异常 字典 | 更新日期: 2023-09-27 17:59:46

在生产中,此代码(C#,.NET 4.5.1)抛出一个ArgumentException,声明An item with the same key has already been added.

代码:

public MyClass()
{
   this.MyContent = new Dictionary<string, string>();            
}
public IDictionary<string, string> MyContent { get; private set; }
public void AddOrUpdateDictionary(string key, string value)
{
    if (this.MyContent.ContainsKey(key))
    {
        this.MyContent[key] = string.Concat(this.MyContent[key], value);
    }
    else
    {
        this.MyContent.Add(key, value);
    }
}

但是,我无法在单元测试中重新创建错误。例如,此行为符合预期-

[TestMethod]
public void AddOrUpdateDictionary_WhenAddingSecondValue_ValueIsAppended()
{
    const string InputValue1 = "Value1";
    const string InputValue2 = "Value2";
    string expectedValue = string.Concat(InputValue1, InputValue2);
    var obj = new MyClass();
    obj.AddOrUpdateDictionary("Key", InputValue1);
    obj.AddOrUpdateDictionary("Key", InputValue2);
    Assert.AreEqual(expectedValue, obj.MyContent["Key"]);
}

是什么原因造成的?我以为ContainsKey会使代码安全。

这是我错过的某个奇怪的线索吗?这段代码位于MVC站点中的一个模型上,没有任何实例是静态的。

字典抛出参数异常,即使受ContainsKey保护

假设问题与线程有关,并且允许更改字典的类型,则可以使用ConcurrentDictionary。它公开了一个方法(AddOrUpdate),该方法可以完全按照预期执行:添加值或根据当前值重构值:

    class MyClass
    {
        public MyClass()
        {
            this.content = new ConcurrentDictionary<string, string>();
        }
        ConcurrentDictionary<string, string> content;
        public IDictionary<string, string> MyContent { get { return content; } }
        public void AddOrUpdateDictionary(string key, string value)
        {
            content.AddOrUpdate(key, value, (k, contentValue) => string.Concat(contentValue, value));   
        }
    }
You may want to use ConcurrentDictionary<T1, T2>

所以它会像:

    public void AddOrUpdateDictionary(string key, string value)
    {
        if (this.MyContent.ContainsKey(key))
        {
            this.MyContent[key] = string.Concat(this.MyContent[key], value);
        }
        else
        {
            this.MyContent.AddOrUpdate(key, value, (x, y) => value);
        }
    }