Invalidating a custom enumerator

Invalidating a custom enumerator

Old forum URL: forums.lhotka.net/forums/t/1108.aspx


SonOfPirate posted on Saturday, September 02, 2006

I have the need to implement my own enumerator for a custom collection class and immediately went to the SortedBindingList for a reference source and was pleased to find that Rocky's implementation was as simple as my approach was - especially considering the half-dozen sources I found online seemed to be building a suspension bridge where a 2x4 would do the trick!

Anyway, I did notice that there is no code addressing invalidation of the enumerator should the source collection be changed after the enumerator was created (e.g. an item added or removed).  I know this is a standard feature of an enumerator but am not quite sure how to implement.

Any good suggestions where I can find examples that cover this aspect of a custom enumerator?

Thanks in advance.

 

Brian Criswell replied on Sunday, September 03, 2006

I do not know if it is a good example, but you can look at the ObjectListView for an example.

SonOfPirate replied on Sunday, September 03, 2006

Thanks, Brian.  That does confirm the approach I had considered for collections implementing the ListChanged event (via IBindingList interface), but I am looking for a solution for more 'primitive' collections - those that implement only IEnumerable<T> or ICollection<T> and have no ListChanged event to handle.

Any ideas how this is done in these cases?

 

Brian Criswell replied on Sunday, September 03, 2006

Well, the Enumerator is invalidated whenever any change is made.  So any call to Move...() or Reset() would need to check every item in the collection.  I don't know how you would practically check that.  Do you have a use case for this?

SonOfPirate replied on Sunday, September 03, 2006

We are implementing several custom collections as part of our efforts but are not implementing IBindingList as they are much simpler objects that this interface provides/requires.  And, I am trying to be as thorough and consistent with the FCL as possible in our own efforts to make it easier for developers to use.

Every 'collection' (everything derived from IEnumerable) provides the ability to retrieve an enumerator for that collection and only System.ComponentModel.BindingList<T> implements IBindingList.  BUT...  All of them fail should the collection be changed while enumerating.  For instance, iterate a System.Collections.Generic.List<T> with a foreach and attempt to remove the item.  You'll get the expected exception.

I'd like to understand how this is done without having some kind of event to catch as is done in ObjectListView.  Obviously, since SortedBindingList does derive from BindingList<T>, it would be easy to add this logic in the same way it is done in ObjectListView to close that gap in the book and source code, but my concern is how the other myriad of collections manage to do the same thing so that we can have consistent behavior with those objects.

Any ideas?

Brian Criswell replied on Sunday, September 03, 2006

Well, enumerators generally have a reference to the list.  You could use a Guid in the list and change the Guid whenever the list changed.  The enumerator could then check if the Guid changed since the last time you called one of the Move...() methods.  You could also use the assembly browser in SharpDevelop (an open source IDE) to look at List<T>'s implementation, as it gives the internal and private members as well.  That might give some extra information than the Visual Studio object browser.

SonOfPirate replied on Sunday, September 03, 2006

How do you accomplish this with SharpDeveloper?  I am familiar with it but was not aware this capability was included?!?  Does this show more than VS's Object Browser or is it more inline with IL DASM?

I did look at the mscorlib.dll using IL DASM and found a _version variable in both the parent collection and nested enumerator.  I am thinking that the collection (List<T> in this case) may increment this value each time a change is made.  Then, when an enumerator is created, the nested Enumerator sets its variable to the parent's value and then uses that to validate itself each time Current, MoveNext or Reset is called.

What do you think?  Sound reasonable?  There really isn't anything else evident in the disassembly to indicate how the objects would be communicating, so I'm thinking this must be it.

 

Brian Criswell replied on Sunday, September 03, 2006

I think it would be closer to IL DASM.  The _version variable is probably what you are looking for.

Copyright (c) Marimer LLC