I am currently writing a class which I would like to make "enumerable" by
inheriting from IEnumerable. The documentation says that the
IEnumerator.MoveNext method should throw an exception if the object being
enumerated has changed since the enumerator was created. Does anyone have
any tips on how best to implement this?
I can think of 2 approaches, neither of which seem very satisfactory. These
are as follows:
1. Take a copy of the class being enumerated when the enumerator is created.
This would be a complete copy, not just a copy of the reference. Then, every
time MoveNext is called, it could compare the current contents to that when
the enumerator was created. This would have a potentially enormous overhead.
2. Have the class being enumerated keep a list of all currently live
enumerators. The class would then inform the enumerators if its contents
changed. This seems like a lot of work to implement something which you
might expect to be straightforward.
An alternative would be to not bother throwing this exception at all.
However this would then break the IEnumerable and IEnumerator specification
which might be considered bad practice.
Thanks,
Tim Davis 6 2008
"Tim Davis" <td***********@ntlworld.com> wrote in message
news:rH**************@newsfe2-gui.ntli.net... I am currently writing a class which I would like to make "enumerable" by inheriting from IEnumerable. The documentation says that the IEnumerator.MoveNext method should throw an exception if the object being enumerated has changed since the enumerator was created. Does anyone have any tips on how best to implement this?
I can think of 2 approaches, neither of which seem very satisfactory. These are as follows:
Personally, I usually use a private version field in the object and change
the version on every modification. When you create an enumerator, you copy
the version value and compare your copy and the objects on every iteration,
if the version changes you have a changed collection.
Depending on your needs, you can probably either use a ulong and simply
increment each time or you could generate GUID's for each version. That
choice is yours.
For what its worth, you should be able to safely change an object without
causing IEnumerator to crash if and only if that change doesn't effect the
results IEnumerator returns. I don't think there is a reason to issue an
exception if some property unrelated to the enumerated contents is set.
Perhaps I'm missing the point, but IEnumerable classes are containers, like
ArrayList and Stack. We don't care if one of the objects within the
container is modified, only if the list itself has been modified (by adding,
deleting, or in some way reordering the list).
Therefore, in your class, set a "dirty" flag if any of these operations
occurs. Clear the "dirty" flag when the enumerator is initialized, and
check it on every MoveNext method call. If it has been set (by the code
adding an entry), throw the error.
Not difficult to implement.
--- Nick
"Tim Davis" <td***********@ntlworld.com> wrote in message
news:rH**************@newsfe2-gui.ntli.net... I am currently writing a class which I would like to make "enumerable" by inheriting from IEnumerable. The documentation says that the IEnumerator.MoveNext method should throw an exception if the object being enumerated has changed since the enumerator was created. Does anyone have any tips on how best to implement this?
I can think of 2 approaches, neither of which seem very satisfactory.
These are as follows:
1. Take a copy of the class being enumerated when the enumerator is
created. This would be a complete copy, not just a copy of the reference. Then,
every time MoveNext is called, it could compare the current contents to that
when the enumerator was created. This would have a potentially enormous
overhead. 2. Have the class being enumerated keep a list of all currently live enumerators. The class would then inform the enumerators if its contents changed. This seems like a lot of work to implement something which you might expect to be straightforward.
An alternative would be to not bother throwing this exception at all. However this would then break the IEnumerable and IEnumerator
specification which might be considered bad practice.
Thanks, Tim Davis
"Nick Malik" <ni*******@hotmail.nospam.com> wrote in message
news:gE7Rc.218528$a24.115525@attbi_s03... Perhaps I'm missing the point, but IEnumerable classes are containers, like ArrayList and Stack. We don't care if one of the objects within the container is modified, only if the list itself has been modified (by adding, deleting, or in some way reordering the list).
Therefore, in your class, set a "dirty" flag if any of these operations occurs. Clear the "dirty" flag when the enumerator is initialized, and check it on every MoveNext method call. If it has been set (by the code adding an entry), throw the error.
There is an issue here with an ordinary boolean dirty flag. Its possible
that a person could generate an IEnumerator, make a change, and generate
another IEnumerator which would reset the dirty flag and would then not
throw an exception when the first IEnumerator calls MoveNext(), even though
it should. Thats why I recommend a full version approach, every change
results in a unique version and every IEnumerator has the version it works
with. You don't have to worry about usage nuances like this. You do have to
consider the maximum enumerations, however, UInt64 allows you to have *ALOT*
of versions.
I don't think this would work if two enumerators were used at the same time.
Consider the following:
Enumerator1 is initialized and the dirty flag is set to clean.
MoveNext is called.
The IEnumerable derivative is then modified so the dirty flag is set to
"dirty".
Enumerator2 is initialized - the dirty flag is then reset to "clean".
When Enumerator1.MoveNext is called again, it wrongly thinks the IEnumerable
derivative is clean.
Regards,
Tim
"Nick Malik" <ni*******@hotmail.nospam.com> wrote in message
news:gE7Rc.218528$a24.115525@attbi_s03... Perhaps I'm missing the point, but IEnumerable classes are containers,
like ArrayList and Stack. We don't care if one of the objects within the container is modified, only if the list itself has been modified (by
adding, deleting, or in some way reordering the list).
Therefore, in your class, set a "dirty" flag if any of these operations occurs. Clear the "dirty" flag when the enumerator is initialized, and check it on every MoveNext method call. If it has been set (by the code adding an entry), throw the error.
Not difficult to implement.
--- Nick
Sounds like a good idea.
Thanks,
Tim
"Daniel O'Connell [C# MVP]" <onyxkirx@--NOSPAM--comcast.net> wrote in
message news:uP**************@TK2MSFTNGP11.phx.gbl... "Tim Davis" <td***********@ntlworld.com> wrote in message news:rH**************@newsfe2-gui.ntli.net...I am currently writing a class which I would like to make "enumerable" by inheriting from IEnumerable. The documentation says that the IEnumerator.MoveNext method should throw an exception if the object
being enumerated has changed since the enumerator was created. Does anyone
have any tips on how best to implement this?
I can think of 2 approaches, neither of which seem very satisfactory. These are as follows:
Personally, I usually use a private version field in the object and change the version on every modification. When you create an enumerator, you copy the version value and compare your copy and the objects on every
iteration, if the version changes you have a changed collection.
Depending on your needs, you can probably either use a ulong and simply increment each time or you could generate GUID's for each version. That choice is yours.
For what its worth, you should be able to safely change an object without causing IEnumerator to crash if and only if that change doesn't effect the results IEnumerator returns. I don't think there is a reason to issue an exception if some property unrelated to the enumerated contents is set.
This actually is a point that gets very involved when you start dealing with
data binding, but I've found using a base class, or interface works quite
well. I just finished writing *ahem* super extended collection base class
from way over the mountain.
In it, I keep a guid that only changes when members are added or removed
from the collection. In additon, the objects it holds implement an
interface (I derived a new one from IEditableObject that adds an
EditStateChanged event). Any time an object in added to the collection, the
collection links on an event handlers and removes it when the item is
removed. The event is raised by the object when it 'changes' and that
causes the collection to also trigger is guid change. Then IEnumerable
implementation just stored the original guid and compares it the the one
currently in the collection before it does an operation. You could use and
other flagging type mechanism also.
If you were using structs in your collection, then you could do a hash on
the entire set and have a good idea that something has changed, but objects
dont change the hash because the default hash (i believe) only compares the
object references. All of this becomes big issues if and when you start
implementing the IBindingList interface.
Hope this helps, a little at least.
"Tim Davis" <td***********@ntlworld.com> wrote in message
news:er*************@newsfe2-gui.ntli.net... I don't think this would work if two enumerators were used at the same
time. Consider the following: Enumerator1 is initialized and the dirty flag is set to clean. MoveNext is called. The IEnumerable derivative is then modified so the dirty flag is set to "dirty". Enumerator2 is initialized - the dirty flag is then reset to "clean". When Enumerator1.MoveNext is called again, it wrongly thinks the
IEnumerable derivative is clean.
Regards, Tim
"Nick Malik" <ni*******@hotmail.nospam.com> wrote in message news:gE7Rc.218528$a24.115525@attbi_s03... Perhaps I'm missing the point, but IEnumerable classes are containers, like ArrayList and Stack. We don't care if one of the objects within the container is modified, only if the list itself has been modified (by adding, deleting, or in some way reordering the list).
Therefore, in your class, set a "dirty" flag if any of these operations occurs. Clear the "dirty" flag when the enumerator is initialized, and check it on every MoveNext method call. If it has been set (by the code adding an entry), throw the error.
Not difficult to implement.
--- Nick
This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Bob Shafer |
last post by:
Is it possible to create dynamic enumerators in Visual
Basic .Net? For example, an enumurator that provides a
dropdown of available SQL servers?
|
by: Matt Taylor |
last post by:
I'm trying to write an x86 assembler in C++ for use in a debugger. What I'd
like do is to use template specialization to prevent invalid combinations
from compiling. Thus one could not accidentally...
|
by: Dave |
last post by:
I have several enums that are generated by a code generator (and I have
no control over the code generator), the problem is that the names are
pretty long
enum VeryLoooooooongEnumName
{...
|
by: Peter Rilling |
last post by:
A design pattern question.
As you know, an enumerator in .NET is broken into two interface (IEnumerable
and IEnumerator). Is there a benefit in having two interfaces? Why not
just have the...
|
by: Andrew Quine |
last post by:
Hi
Short one: looking for a good example and an explanation of such
enumerators. I know MessageEnumerator and ResourceReader do this, for
example, but what is the implementation of the...
|
by: juan |
last post by:
hi i have an arraylist that has doctor objects with various properties,
members and methods.
i want to enumerate this arraylist object.
but i dont understand how.
this is what i have done
...
|
by: psbasha |
last post by:
Hi ,
Does Python supports enumerators?
enum{
Red=1,
Gren,
Blue,
Orange}
|
by: muaddubby |
last post by:
Hello all and happy new year.
I've seen several posts floating around asking about string enumerators in C#, and generally speaking, they're not supported.
I've come up with a way around it...
|
by: nitindel |
last post by:
Hi All,
May i have an in depth article of enumerators in C#..that explains the Enumerators in C# very precisely....
Thanks,
Nitin
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: aa123db |
last post by:
Variable and constants
Use var or let for variables and const fror constants.
Var foo ='bar';
Let foo ='bar';const baz ='bar';
Functions
function $name$ ($parameters$) {
}
...
|
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...
|
by: ryjfgjl |
last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
|
by: emmanuelkatto |
last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud.
Please let me know.
Thanks!
Emmanuel
|
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...
|
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: Hystou |
last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
| |