views:

409

answers:

3

Suppose I have a class TestCollection which is used to hold objects of type Test and is defined as

public class TestCollection : CollectionBase

This allows me to iterate through the collection either as

foreach(object o in collection)
...

or

foreach(Test t in collection)

but does not allow me to use new Linq queries.

If I change the definition of the class to

public class TestCollection : CollectionBase, IEnumerable<Test>

and add a method

public new IEnumerator<Test> GetEnumerator()
{
    foreach (Test o in this.List)
        yield return o ;
}

then linq queries are available.

However this new method is not just called for linq queries, but is also called in the legacy code (ie during the foreach(object o in collection) and foreach(Test in Collection).

Is there any difference between the old way of iterating through the collection and this new way assuming all the items in the collection are of type Test? I am aware that adding the IEnumerator method will cause the program to throw an exception if it finds any types other than Test, but want to know if I have overlooked anything.

A: 

The IEnumerator<T> compiled from an iterator doesn't implement the Reset method. EDIT: I mean that it will throw a NotImplementedException.

There's nothing actually wrong with that, but if you want the Reset method, you'll have to write your own iterator class, which isn't hard.

SLaks
No; it *implements* it - as throwing a `NotImplementedException`. Iterator blocks are fine for this purpose.
Marc Gravell
That's what I meant.
SLaks
+1  A: 

No, you will see identical results and only experience a single extra level of indirection (as the new GetEnumerator method simply calls the existing GetEnumerator method and streams its output).

Andrew Hare
+8  A: 

Since you are in 2.0 (or above), perhaps just inherit from Collection<T>?

public class TestCollection : Collection<Test> {
    // your extra code here
}

Then you get IList<T>, ICollection<T>, IEnumerable<T> for free, and virtual methods that you can override to put your stamp on the behaviour.

Marc Gravell
+1 That's a good idea too.
Andrew Hare
+1 .. i agree with this.
Stan R.
Changing a base type is a breaking change - if the class has already shipped, this should not be done.
SLaks
If the class has not already shipped, this definitely should be done.
SLaks
Didn't want to inherit from Collection<Test> at the moment, because I was hoping to get something for free (or almost free) (ie that needs very little testing.)Changing to inherit from Collection<T> sounds like quite a big change (ie would need lots of testing).Also. the actual scenario is more complicated than my example. There will be classes which are derived from Test (say Test2) which have their own collections classes and inheriting Test2Collection from either Collection<Test2> or TestCollection doesn't work well.
sgmoore