By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
434,998 Members | 2,871 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,998 IT Pros & Developers. It's quick & easy.

Avoiding "enumeration modified" Exception

P: 19
For my program i need a great deal of completely random, unique, 12 character id's.

So i wrote these three functions

Expand|Select|Wrap|Line Numbers
  1.  
  2. public static string GiveUniqueID(IEnumerator id_key, int count)
  3. {
  4. string id = "";
  5. bool done = false;
  6. while (!done)
  7. {
  8. id = CreateUniqueID(id_key, count);
  9.  
  10. if (id != "@@@")
  11. done = true;
  12. }
  13.  
  14. return id;
  15. }
  16.  
  17. public static string CreateUniqueID(IEnumerator id_key, int count)
  18. {
  19. List<string> ids = new List<string>();
  20. for(int i = 0; i < count; ++i)
  21. {
  22. try
  23. {
  24. id_key.MoveNext();
  25. ids.Add((string)id_key.Current);
  26. }
  27. catch (Exception)
  28. {
  29. return "@@@";
  30. }
  31. }
  32.  
  33. bool done = false;
  34. string id = "";
  35. while (!done)
  36. {
  37. id = UniqueID();
  38.  
  39. if (!ids.Contains(id))
  40. done = true;
  41. }
  42.  
  43. return id;
  44. }
  45.  
  46. public static string UniqueID()
  47. {
  48. string toreturn = Session.IdPrefix;
  49. for (int i = 0; i != 10; ++i)
  50. toreturn += Utility.RandomList(1, 2, 3, 4, 5, 6, 7, 8, 9, 0).ToString();
  51.  
  52. return toreturn;
  53. }
  54.  
So when i need a unique id i simply go string s = GiveUniqueID();, but every while and then the program will freeze because the exception "enumeration modified" keeps repeating in an endless loop.

I am passing the Keys.GetEnumerator(); of dictionaries of varying value types and the count of the dictionary. Since the dictionary's are of varying types i cannot simply pass the dictionary as an argument.

So what i am asking is how to avoid this endless loop?
Dec 31 '08 #1
Share this Question
Share on Google+
5 Replies


vekipeki
Expert 100+
P: 229
Well, first of all, you should never catch an exception just to ignore it. Remove the try/catch block because you actually want to break the program flow when something goes wrong.

Passing strings with special meanings such as "@@@" is not a very good practice, it will make your code really hard to read, so you should also avoid it.

Are you sure that your exception is "Enumeration modified"? It does not seem that you are actually modifying the enumeration.

My suggestion is to use an IDictionary parameter instead of IEnumerator, it will give you .Count and .Contains(), so you don't have to copy it to a new list every time. Or you can at least use IEnumerable instead of IEnumerator to simplify your code a bit.

Try something like this:

Expand|Select|Wrap|Line Numbers
  1. public static string CreateUniqueID(IDictionary dictionary)
  2. {
  3.     String id = UniqueID();
  4.  
  5.     // Check if our dictionary already contains this key.
  6.     while (dictionary.Contains(id))
  7.         id = UniqueID();
  8.  
  9.     return id;
  10. }
You can also consider using System.Guid class, it generates random GUIDs so you don't have to do it yourself:

Expand|Select|Wrap|Line Numbers
  1. String guid = Guid.NewGuid().ToString();
And please use the CODE tags when posting ! :o)
Dec 31 '08 #2

Plater
Expert 5K+
P: 7,872
I was wondering what happens if you call that function again before the first one is done?
Dec 31 '08 #3

P: 19
Its a multi thread program, which primarily operates in system memory but uses a database to communicate and synchronize with other instances of the program over the network, so the thread that is synchronizing system data with the database is modifying the dictionary I'm trying to find a unique id for, and to prevent duplicate id's from this i give each client a 2 character id prefix such as "aa".

i managed to fix this problem however simply by making sure it does not endlessly loop, however the problem i have run into now is that the synchronization process is extremely slow, as to read the results of a query the synchronization thread waits on the query thread, this results in only one query being executed while i wait for the result, where as what im aiming for is the execution of many queries without waiting for results.
Jan 1 '09 #4

vekipeki
Expert 100+
P: 229
If your ID doesn't have to be a 10-character string, it would be easiest to simply use:
Expand|Select|Wrap|Line Numbers
  1. String id = Guid.NewGuid().ToString();
This will give you a unique ID every time, without a need for any checks - but it is actually be a hex representation of a 128-bit number.

If you have a really large dictionary, then you will obviously spend some time looking for a unique 10-digit ID (Birthday Paradox is a good sample of collision statistics).

Also, if you are still using try/catch, note that it is one of the largest performance bottlenecks - each caught exception really slows down execution.
Jan 2 '09 #5

Plater
Expert 5K+
P: 7,872
Only the generation of new unique IDs has to be done "one at a time" right? So its ok for your other queries to happen all the time?
Consider only waiting when it deals with the ID generation?
Jan 2 '09 #6

Post your reply

Sign in to post your reply or Sign up for a free account.