I'm working on maintenance of a .NET project, and I'm having some troubles which I'll gladly share with you guys =)
The problem code:
if( evilDict.Count < 1 )
{
foreach (Item item in GetAnotherDict())
if (!evilDict.containsKey(item.name.ToLower().Trim()))
evilDict.add(item.name.ToLower().Trim(), item.ID);
}
Despite the contains()-check, I'm getting an ArgumentException telling me that an item with the same key has already been added. We have only gotten this problem in production, never in testing, which makes me suspect a concurrency problem. What I'm wondering is:
Here's my potential fix, replacing the dictionary.add() thing
protected static void DictAddHelper(Dictionary<String, int> dict, String key, int value)
{
lock (dict)
{
key = key.ToLower().Trim();
if (dict.ContainsKey(key) == false)
{
try
{
dict.Add(key, value);
}
catch (ArgumentException aex)
{
StringBuilder debugInfo = new StringBuilder();
debugInfo.AppendLine("An argumentException has occured: " + aex.Message);
debugInfo.AppendLine("key = " + key);
debugInfo.AppendLine("value = " + value);
debugInfo.AppendLine("---Dictionary contains---");
foreach (String k in dict.Keys)
debugInfo.AppendLine(k + " = " + dict[k]);
log.Error(debugInfo, aex);
}
}
}
}
EDIT:
Suggestions that don't require me to make a thread-safe implementation of the Dict class are better, since it would be a pretty big refactoring that won't be a very welcome suggestion =)
EDIT2:
I tried
lock (((IDictionary)dict).SyncRoot)
But I get
Error 28 Using the generic type 'System.Collections.Generic.IDictionary<TKey,TValue>' requires '2' type arguments
Then I try this:
lock (((IDictionary<String, int>)dict).SyncRoot)
Error:
Error 28 'System.Collections.Generic.IDictionary<string,int>' does not contain a definition for 'SyncRoot'
FINAL EDIT (I guess):
Thanks for all the answers!
Now, all I want to know is this. Will my method (DictAddHelper) work at all, and if not, why?
For very large Dictionary objects, you can increase the maximum capacity to 2 billion elements on a 64-bit system by setting the enabled attribute of the gcAllowVeryLargeObjects configuration element to true in the run-time environment. Source.
It is thread-safe and internally uses locking. It is useful in the case of a multi-threaded application.
It's a dictionary of dictionaries, so you have 2 keys to access each object, the key for the main dictionary to get you the required sub dictionary, and then the second key for the sub dictionary to get you the required item.
C# Dictionary class constructor takes a key data type and a value data type. Both types are generic so it can be any . NET data type. The following Dictionary class is a generic class and can store any data type.
If you suspect you have concurrency problems accessing the dictionary then your fix won't be of any use. It will solve the specific problem you are experiencing, however if you have concurrent access to the dictionary you are going to have more problems in the future.
Consider locking the access to the dictionary when you are modifying it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With