2
votes

I am getting an IndexOutOfRange exception while adding values to Generic dictionary (WinRT C#). Below is my code and stack trace of exception.

Code:

if (!data.TryGetValue(index, out cells))
{
   cells = new CellCollection();
   data.Add(index, cells);
}

Stack trace:

at System.Collections.Generic.Dictionary2.Insert(TKey key, TValue value, Boolean add) at System.Collections.Generic.Dictionary2.Add(TKey key, TValue value)

I wouldn't expect this out of range exception occurs while adding. My application uses single thread only. I have add values to dictionary and remove it from dictionary using GC.Collect() if not needed. And then add the value if needed.

Can anyone give any suggestion to resolve this exception?

1
I guess you're accessing a dictionary in multiple threads without proper synchronization which is not safe. Are you? Edit: I saw in question you mentioned My application uses single thread only but make sure you cross check to see if the dictionary slipped to another thread.Sriram Sakthivel
If it's not a concurrency issue (or if you decide you need help solving that) you'll have to post a better question, with a complete-but-concise code example. There's very little information to go on here so far. See stackoverflow.com/help/mcve for more information on posting a good code example.Peter Duniho
I agree it sounds like you have multiple threads, as in .AsParallel() of Parallel.ForEach or something. However, can we see what TKey, i.e. the type of index is?Jeppe Stig Nielsen
I didn/t use multiple threads in my application. The only thing I did, remove items from the dictionary using Finalize method (Desctructor of the class). In My dictionary, Tkey is integer (int) type and Tvalue is another generic dicitionary.Selvamz
@Selvamz A finalizer is called from a separate thread, so that could be causing issues. (Also: never ever access managed objects from a finalizer. It's for use with unmanaged objects only.)Matthew Watson

1 Answers

4
votes

During a call to Dictionary<,>.Add it will sometimes be necessary to allocate a new backing array because the Count exceeds the current capacity of the Dictionary<,>. When allocating a new managed object (the new array) the garbage collector might set in. Your application is "paused" and garbage collection takes place. Then after garbage is collected, control resumes from where you were inside the Add method, and the new backing array is filled with data from the old one.

However, based on your comments to your question above, you have finalizers. There must exist an unrelated object (maybe another instance of the same class) that is being finalized. It seems it holds a reference to the same Dictionary<,>. During the finalization, your destructor code, you change the state of the Dictionary<,>. Then when the main thread resumes control after the garbage collection, the state of the Dictionary<,> has been changed, but we were in the middle of a process of adding one new element to that Dictionary<,>.

The lesson learned is: Do not write destructors (finalizers). If you do anyway, do not change the state of managed objects that are (can be) referenced from elsewhere (i.e. from "living" objects that will not be collected).

Matthew Watson said it in a comment to your question.