473,378 Members | 1,504 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,378 software developers and data experts.

IEnumerator Usage

I've been kicking around an idea mostly as a thought experiment at this
point. The idea is to create a thread safe collection that implements
the IEnumerable interface. The enumerators it creates via the
GetEnumerator method would be synchronized with the collction; if the
collection changes, the existing enumerators are notified via an event.
The accompanying EventArgs derived class object carries information
about the change to the collection so that the enumerators can update
themselves to keep the enumerations in sync.

This type of approach allows enumeration over a collection while it is
being changed without an exception being thrown. This type of approach
may be useful to me at some point in the future.

My question is this: the IEnumerator interface specification for the
MoveNext method states that an InvalidOperationException will be thrown
if the collection is modified after the enumerator was created. Using
the approach I described above, this would no longer be the case. So
would it be considered bad design to implement the IEnumerator interface
but not enforce this precondition? Should I abandon implementing the
IEnumerator interface?

The advantage of using the IEnumerator interface is it allows
enumerators to be used seamlessly with the foreach construct, so I would
really like to use it but have my doubts about weakening the IEnumerator
specification. Thoughts?
May 17 '06 #1
11 2189
"Leslie Sanford" <ja**********@BiteMeHotmail.com> wrote:
My question is this: the IEnumerator interface specification for the
MoveNext method states that an InvalidOperationException will be thrown
if the collection is modified after the enumerator was created. Using
the approach I described above, this would no longer be the case. So
would it be considered bad design to implement the IEnumerator interface
but not enforce this precondition?


No!

That's my take on it. Also think of "yield return" and iterator
blocks, which offer the IEnumerator interface even though they don't
even have a collection at all.

I've even used IEnumerator to enumerate over values that must be
removed from a collection, where I *require* the value to be removed
from the collection before calling MoveNext. (because that was how the
"must-be-removed" algorithm worked). (nb. with values rather than
references.)

--
Lucian
May 17 '06 #2
It is a bad design. When you iterate over a collection you are
interested in the collection's state at the moment you invoked the
iteration (these are the semantics).

Imagine having to take a decision a particular moment about an event
while iterating a collection that you cannot be sure if it has been
changed or not.

If you want to create a producer/consumer pattern you should consider
an alternative design.

As the MSDN documentation states "Enumerating through a collection is
intrinsically not a thread-safe procedure".

Regards,
Tasos

May 17 '06 #3

"Tasos Vogiatzoglou" wrote:
It is a bad design. When you iterate over a collection you are
interested in the collection's state at the moment you invoked the
iteration (these are the semantics).

Imagine having to take a decision a particular moment about an event
while iterating a collection that you cannot be sure if it has been
changed or not.
Consider this example: Suppose you have a program for playing/editing
MIDI files (my area of expertise). MIDI files are made up of tracks
which are themselves made up of MIDI events. In other words, each track
is a collection of MIDI events.

Say that you would like to edit a track as it is being played. For
example, you may want to move an event forward in time or delete it.

Playing a MIDI file essentially involves iterating over the collection
of MIDI events in each track (with the speed of the iteration being
driven by timing events). If you want to edit these tracks as they are
being played, you are modifying a collection as it is being iterated
over.

So with the above scenario, I was thinking of creating iterators that
are capable of keeping themselves in sync with the track collections as
they are being modified.

IEnumerator aside, would this be considered bad design?
If you want to create a producer/consumer pattern you should consider
an alternative design.
Hmm, I will study the producer/consumer approach. Given the above
description, can you suggest a way of applying producer/consumer to my
problem?
As the MSDN documentation states "Enumerating through a collection is
intrinsically not a thread-safe procedure".


This is true of true of the collection classes provided by the .NET
framework, but does it have to hold true for your own custom collection
classes?
May 17 '06 #4
A "rough" approach (if I understood the problem correctly):

You have collection A that holds MIDI events. You have a thread PLAYER
that iterates through the collection at specified intervals. If you
modify collection A at position POS you can notify the PLAYER to stop
the iteration and begin again at the position that stopped. That way
the PLAYER will get the latest change (if it was at the position of
editing).

This could be one approach without having to resort to a IEnumerable
that ignores collection changes.

I don't think that producer/consumer applies well to this problem.

The rules are meant to be broken of course and because .NET
documentation says so this doesn't mean that you can't create such a
collection. But I personally believe that this may introduce bugs that
are not immediately visible ( or addressable) .

Regards,
Tasos

May 17 '06 #5
"Leslie Sanford" <ja**********@BiteMeHotmail.com> schrieb im Newsbeitrag
news:_p******************************@comcast.com. ..
I've been kicking around an idea mostly as a thought experiment at this
point. The idea is to create a thread safe collection that implements the
IEnumerable interface. The enumerators it creates via the GetEnumerator
method would be synchronized with the collction; if the collection
changes, the existing enumerators are notified via an event. The
accompanying EventArgs derived class object carries information about the
change to the collection so that the enumerators can update themselves to
keep the enumerations in sync.

This type of approach allows enumeration over a collection while it is
being changed without an exception being thrown. This type of approach may
be useful to me at some point in the future.

<snip>

Hi Leslie,

i think the greatest problem with this is, clearly defining the semantic.
I mean, how should the enumerator react if certain changes occur in the
underlying list. If that's clearly defined than your approach could work.
But maybe Tasos is right, that Enumarator is not the design for your
solution

HTH
Christof
May 17 '06 #6
Leslie,

I agree with the majority of the opinions here that it is bad design.
The interface implies a contract, and you are violating that. It's not
something to be taken lightly, IMO. There are semantics that users of the
iterface you implement assume, and if you violate that, then their claims
about what they can do can't be enforced, and so on and so on.

To make your collection thread safe, I would offer one of the following:

- Throw an exception when the enumeration is changed
- Use locks to block changes on the collection while it is being enumerated
- Take a snapshot of the collection while enumerating and have the
enumerator use that instead of the store that is being modified.

Hope this helps.
--
- Nicholas Paldino [.NET/C# MVP]
- mv*@spam.guard.caspershouse.com
"Leslie Sanford" <ja**********@BiteMeHotmail.com> wrote in message
news:_p******************************@comcast.com. ..
I've been kicking around an idea mostly as a thought experiment at this
point. The idea is to create a thread safe collection that implements the
IEnumerable interface. The enumerators it creates via the GetEnumerator
method would be synchronized with the collction; if the collection
changes, the existing enumerators are notified via an event. The
accompanying EventArgs derived class object carries information about the
change to the collection so that the enumerators can update themselves to
keep the enumerations in sync.

This type of approach allows enumeration over a collection while it is
being changed without an exception being thrown. This type of approach may
be useful to me at some point in the future.

My question is this: the IEnumerator interface specification for the
MoveNext method states that an InvalidOperationException will be thrown if
the collection is modified after the enumerator was created. Using the
approach I described above, this would no longer be the case. So would it
be considered bad design to implement the IEnumerator interface but not
enforce this precondition? Should I abandon implementing the IEnumerator
interface?

The advantage of using the IEnumerator interface is it allows enumerators
to be used seamlessly with the foreach construct, so I would really like
to use it but have my doubts about weakening the IEnumerator
specification. Thoughts?

May 17 '06 #7

"Tasos Vogiatzoglou" wrote:
A "rough" approach (if I understood the problem correctly):

You have collection A that holds MIDI events. You have a thread PLAYER
that iterates through the collection at specified intervals. If you
modify collection A at position POS you can notify the PLAYER to stop
the iteration and begin again at the position that stopped. That way
the PLAYER will get the latest change (if it was at the position of
editing).

This could be one approach without having to resort to a IEnumerable
that ignores collection changes.


This is a good suggestion. Instead of trying to shoehorn
IEnumerable/IEnumerator into my design, I could instead have a class
dedicated to playback and keeping track of changes to the collection so
that the playback is synchronized. Thanks for your response.
May 17 '06 #8
"Nicholas Paldino [.NET/C# MVP]" <mv*@spam.guard.caspershouse.com>
wrote:
I agree with the majority of the opinions here that it is bad design.
The interface implies a contract, and you are violating that.


It's an odd sort of contract, though. This contract that you're
violating is a contract about what ISN'T supported (modifying the
collection in flight), rather than one about what IS supported. So the
only clients who would be affected by the proposal are those who
*rely* upon the "CollectionChanged" exception. And I'd call those
clients broken.

--
Lucian
May 18 '06 #9
Lucian,
At first it may seem like an odd contract, but you are not violating a
contract about what is not supported, you violate the intented usage
pattern.

If you bring new developers to your project, when they will see a
collection they will assume that they can iterate the collection just
keeping in mind the case of concurrent modifications. But by violating
that contract, you give to your co-developers an IEnumerable with
broken semantics.

Noone excpects an infite loop for example for a collection enumeration,
something that can happen if you violate the (implied at least)
pattern.

Regards,
Tasos

May 18 '06 #10
"Tasos Vogiatzoglou" <tv*****@gmail.com> wrote:
Noone excpects an infite loop for example for a collection enumeration,
something that can happen if you violate the (implied at least)
pattern.


I don't see it. I mean, the only way the code would get an infinite
loop is if another thread was modifying the collection. So in the
original semantics this would have caused a fault (exception). And in
the new semantics it also causes a fault (infinite loop). All clients
who expected the original semantics will have avoided the exception,
and so their code will work exactly in the same way, unchanged, with
the new semantics. So this is a "conservative" extension to the
semantics -- it doesn't break anything, it merely adds new
functionality.

--
Lucian
May 18 '06 #11
I agree. But in the "original semantics" there is a fail-fast
assurance. If there is a concurrent modification then you have an
exception. The "new semantics" are more prone to race conditions
(comparing to the original ones).

If I were to design such a system, I would first check the alternatives
but if nothing was a good solution of course I would go with your way
....

What I am saying is that, it's a risky choice.

Regards,
Tasos

May 18 '06 #12

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

9
by: Sasha | last post by:
Hi, I am extending standard IEnumerator, and I was just wondering what is the best way to make enumarator safe? What do I mean by safe? Detect deletes and all... My idea is to have private Guid...
1
by: juan | last post by:
hi i have a teachers class where i want the user to enter a few teachers and iterate thru them. In the main i get an error System.Collections.IEnumerator' does not contain a definition for...
3
by: Hans | last post by:
I implemented the IEnumerator interface in some classes to enable the use of the foreach statement. As you probalbly know, the interface asks for the implementation of object IEnumerator.Curren...
3
by: starter | last post by:
I am trying to learn IEnumerator and collections(ArrayList, Hashtable) in .NET. Can anyone tell me what is IEnumerator used for and any online resources would be helpful. Thanks
1
by: midnight madness | last post by:
I tried but failed to implement a template class that support IEnumerator<T> interface using C++/CLI in VS 2005 Professional version. I could not figure out the proper syntax to implement the...
5
by: Shikari Shambu | last post by:
Hi, I am trying to implement a collection that implements IEnumerable<T>. I keep getting the following error 'IEnumerator<...>.Current' in explicit interface declaration is not a member of...
3
by: EmilH | last post by:
Hi. I have read some examples of IEnumerator at http://www.codeproject.com/csharp/csenumerators.asp What if I have 2 arrays or collections, for example a DataSet which has 2 DataTables in my...
3
by: cody | last post by:
Currently it is only legal to use types which has a method named GetEnumerator to be used in a foreach loop. This makes it impossible to use the same Enumerator after and before a foreach loop,...
2
by: Henri.Chinasque | last post by:
I have a feeling this is a dumb one, but here it is: IEnumerator<Timplements IDisposable, but the thing is I'm not sure what I'm supposed to dispose! I'm also curious why IEnumerator<T>...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: taylorcarr | last post by:
A Canon printer is a smart device known for being advanced, efficient, and reliable. It is designed for home, office, and hybrid workspace use and can also be used for a variety of purposes. However,...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.