Silly C# Dictionary Error

So, I stumbled across an interesting error while coding today, which in hindsight is really simple (less tactful and more self-deprecating would be to say “stupid”). In C# (3.0), there is a set of classes that supply you with some really common generic data structures, such as the Stack or the Queue. Using generics, you specify the type(s) such that you can have handy, type-safe collections to work with.

In a small bit of code, I was making use of the Dictionary, more specifically Dictionary. I was first filling it with keys only, which corresponded to specific pages in a large PDF. I then iterated (foreach) through said Dictionary a second time, chopping up the large PDF based on the indexed pages, creating smaller ones, and putting the resultant file name in the value part of the KeyValuePair. Many times, we fill and iterate in a read-only way with the structures, so this error is uncommon if you forget something basic about them.

When first stepping through my code, on the second foreach block, I got a “Collection was modified; enumeration operation may not execute.” Wha? I had forgotten that you will get this error if any reference in the Dictionary gets changed to a new reference. IOW, if you take an instance of a class that is stored in the Dictionary and replace it with a different one, while looping, the IEnumerator notices the change and chokes on the “dirty” collection.

You are allowed to change the properties of objects stored in your collection, though. So, a simple fix is that instead of using a string, which is immutable, and doing something like:

Dictionary pageDictionary<int,string> = new Dictionary();
...
for (int i = 1; i <= theDoc.PageCount; i++)  // first loop
{
  pageDictionary.Add(theDoc.PageNumber, "")
}
...
foreach (KeyValuePair<int,string> idxPair in pageDictionary)  // second loop
{
  pageDictionary[pageIndex] = extractFileName;
}

You should use StringBuilder, which is like String, but mutable:

Dictionary pageDictionary<int,StringBuilder> = new Dictionary();
...
for (int i = 1; i <= theDoc.PageCount; i++)  // first loop
{
  pageDictionary.Add(theDoc.PageNumber, "")
}
...
foreach (KeyValuePair<int,StringBuilder> idxPair in pageDictionary)  // second loop
{
  pageDictionary[pageIndex].Append(extractFileName);
}

Duh. Silly me.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s