Saturday, January 18, 2020

Hello, dear readers!

Today I would like to share with you some tips regarding debugging the so called "Collection Was Modified Exception".
Often, this problem arises when a collection is changed during its enumeration with a foreach statement. The debugging is quite straightforward:
1) get to the problematic foreach statement;
2) set breakpoints in all the places in a code where the enumerated collection is modified;
3) run through the foreach body.
4) find the place of an unexpected collection modification.

But what to do if the collection modification is not so obvious or if the collection is modified in a lot of places? In these situations I prefer temporarily switching the enumerated collection with a special wrapper that is created with a sole purpose of identifying such a situation.

Lets consider a common System.Collections.Generic.List<T>. To create a wrapper that would automatically identify the "Collection Was Modified" situation follow these steps:

1) Create a stub for a new class ChangedDuringEnumerationMonitoringList<T> : IList<T> with an inner List<T> instance:
1:  class CollectionChangedDuringEnumerationMonitoringList<T> : IList<T>  
2:  {  
3:      readonly List<T> _list = new List<T>();  
4:  }  

2) Automatically implement all the IList<T> members by delegating to the inner _list. For example:
1:  public void Add(T item) 
2:  { 
3:      _list.Add(item); 
4:  } 

3) Implement custom IEnumerator<T> that delegates all its functionality to an original enumerator of a list and tells whether it is in a state of enumeration:
1:  public class NotifyingEnumeratorWrapper : IEnumerator<T>, IEnumerator  
2:  {  
3:      // An original enumerator that is delegated to.  
4:      readonly IEnumerator<T> _typedEnumerator;  
5:    
6:      // Injecting an original enumerator instance in a constructor.  
7:      public NotifyingEnumeratorWrapper(IEnumerator<T> enumerator)  
8:      {  
9:          _typedEnumerator = enumerator;  
10:      }  
11:    
12:      // A property that marks that an enumeration is in a progress.  
13:      public bool IsEnumerating { get; private set; }  
14:    
15:      public void Dispose()  
16:      {  
17:          IsEnumerating = false;  
18:          _typedEnumerator?.Dispose();  
19:      }  
20:    
21:      public bool MoveNext()  
22:      {  
23:          IsEnumerating = true;  
24:          return _enumerator.MoveNext();  
25:      }  
26:    
27:      // The rest of the implementation.  
28:  }  
29:  

4) And finally, modify your custom IList<T> implementation to check whether a collection is modified during an enumeration:
1:  class CollectionChangedDuringEnumerationMonitoringList<T> : IList<T>  
2:  {  
3:      NotifyingEnumeratorWrapper _enumerator;  
4:    
5:      public IEnumerator<T> GetEnumerator()  
6:      {  
7:          _enumerator = new NotifyingEnumeratorWrapper(_list.GetEnumerator());  
8:          return _enumerator;  
9:      }  
10:    
11:      public void Add(T item)  
12:      {  
13:          // Add this call for every IList<T> member that modifies a collection.  
14:          OnCollectionChangedDuringEnumeration();  
15:          _list.Add(item);  
16:      }  
17:    
18:      void OnCollectionChangedDuringEnumeration()  
19:      {  
20:          if (_enumerator != null) {  
21:              if (_enumerator.IsEnumerating) {  
22:                  // Setting a breakpoint here will stop a program exactly at the moment  
23:                  // that collection is modified during an enumeration.
24:                  System.Diagnostics.Debugger.Break();  
25:              }  
26:          }  
27:      }  
28:    
29:      // The rest of the implementation.   
30:  }  
31:    

Now you are all set to go. Switch the List type of your collection that has troubles enumerating for this new custom ChangedDuringEnumerationMonitoringList. Then run your application as usual to reproduce the "Collection Was Modified Exception". And the moment your collection is modified during enumeration your application will stop at the breakpoint. Now you can simply observe the stack trace and get straight to fixing your bug!

Having a custom list such as this in your toolbox makes detecting the source of "Collection Was Modified" problem as easy as two Copy/Paste to replace the collection type and one application run to reproduce the bug.

Feel free to take a look at the full implementation of the ChangedDuringEnumerationMonitoringList on my SpaceStrategy GitHub repository.

What are the techniques you are using to find the cause of the "Collection Was Modified Exception"? Please share them here in comments.

Sunday, January 12, 2020

Now on GitHub!

Hello, everyone!

A few days ago I have published the source code of the SpaceStrategy on GitHub. Feel free to take a look and leave some comments!

I've published the code on GitHub mainly to sharpen my GitHub skills. But don't expect much as the code is pretty old, and now even I am terrified looking at some parts of it. But let's be positive and get some benefits from this situation! It is a great chance to practice some heavy code refactoring and restyling.

First of all, I have decided to bring a code formatting and style into an order:

  • newlines and spaces;
  • ordering of members;
  • naming and typos;
  • etc.

The solution being 130+ files with a style all over the place it is a tough task to accomplish by hand. So I decided to try out some tools.

At first I wanted to try out something new and selected the most recent and the most downloadable tool of the Visual Studio Marketplace for the task. It happened to be the CodeMaid. It was easy to configure and produced good formatting results. The "automatic cleanup on save" feature proved to be quite useful. But in the end, I wasn't able to configure automatic formatting to my liking. Personally, the most troubling was the formatting of properties.

Being a little bit disappointed, I turned back to the Resharper. It not only allowed me minutely configure almost every imaginable setting for automatic code formatting, but also provided a lot of features for manual code refactoring: spellchecking, quick-fixes, recommendations and more. It helped me to automate an enormous amount of tedious work, and I was able to cleanup my code in a matter of hours. Just take a look at recent commits in my SpaceStrategy repository on GitHub and see the results for yourself.

Stay tuned and I will try to provide some new exciting materials about programming my game.