1

This code is not compiling, and it's throwing the following error:

The type 'TestesInterfaces.MyCollection' already contains a definition for 'Current'

But when I delete the ambiguous method, it keeps giving other errors.

Can anyone help?

public class MyCollection<T> : IEnumerator<T>
{
    private T[] vector = new T[1000];
    private int actualIndex;

    public void Add(T elemento)
    {
        this.vector[vector.Length] = elemento;
    }

    public bool MoveNext()
    {
        actualIndex++;
        return (vector.Length > actualIndex);
    }

    public void Reset()
    {
        actualIndex = -1;
    }

    void IDisposable.Dispose() { }

    public Object Current
    {
        get
        {
            return Current;
        }
    }


    public T Current
    {
        get
        {
            try
            {
                T element = vector[actualIndex];
                return element;
            }
            catch (IndexOutOfRangeException e)
            {
                throw new InvalidOperationException(e.Message);
            }
        }
    }
}
hopper
  • 13,060
  • 7
  • 49
  • 53
Marcel James
  • 834
  • 11
  • 20
  • 1
    Is there a reason why you're implementing `IEnumerator` instead of `IEnumerable`? This implementation seems to be asking for issues with threadsafety (multiple enumerations look like they will fail spectacularly) – Chris Sinclair Aug 07 '13 at 13:46
  • yeah, I'm just playing with the collections to understand the inner workings, not just how to use them :) – Marcel James Aug 07 '13 at 14:50

3 Answers3

12

I think you're misunderstanding IEnumerator<T>. Typically, collections implement IEnumerable<T>, not IEnumerator<T>. You can think of them like this:

  • When a class implements IEnumerable<T>, it is stating "I am a collection of things that can be enumerated."
  • When a class implements IEnumerator<T>, it is stating "I am a thing that enumerates over something."

It is rare (and probably wrong) for a collection to implement IEnumerator<T>. By doing so, you're limiting your collection to a single enumeration. If you try to loop through the collection within a segment of code that's already looping through the collection, or if you try to loop through the collection on multiple threads simultaneously, you won't be able to do it because your collection is itself storing the state of the enumeration operation. Typically, collections (implementing IEnumerable<T>) return a separate object (implementing IEnumerator<T>) and that separate object is responsible for storing the state of the enumeration operation. Therefore, you can have any number of concurrent or nested enumerations because each enumeration operation is represented by a distinct object.

Also, in order for the foreach statement to work, the object after the in keyword, must implement IEnumerable or IEnumerable<T>. It will not work if the object only implements IEnumerator or IEnumerator<T>.

I believe this is the code you're looking for:

public class MyCollection<T> : IEnumerable<T>
{
    private T[] vector = new T[1000];
    private int count;

    public void Add(T elemento)
    {
        this.vector[count++] = elemento;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return vector.Take(count).GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
  • i im not really planning to use this collection im creating... I'm only doing this to try to understand the functioning of the IEnumerator and IEnumerable... anyways your implementation throws *'System.Collections.Generic.IEnumerator' requires 1 type arguments* – Marcel James Aug 07 '13 at 14:43
  • You need both `using System.Collections;` and `using System.Collections.Generic;` if your code uses both `IEnumerable` and `IEnumerable`. – Michael Gunter Aug 07 '13 at 15:49
  • thats true, im sorry. Your example of how thinking IEnumerator and IEnumerable helped me. Thanks – Marcel James Aug 07 '13 at 16:29
  • @MichaelGunter `It is rare (and probably wrong) for a collection to implement IEnumerator.` Is this [example](https://msdn.microsoft.com/en-us/library/9eekhta0(v=vs.110).aspx#Anchor_4) one of them? – ibubi May 26 '17 at 14:36
  • @ibubi : No. The code in that example shows what I would expect all `IEnumerable`/`IEnumerator` implementations to be -- separate classes for the `IEnumerable` and the `IEnumerator`. – Michael Gunter Jun 01 '17 at 16:53
9

You need to define the interface the current is implementing.

Object IEnumerator.Current
{
    //
}

public T Current
{
    //
}

This way your class has 2 Current properties. but you can access them both.

MyCollection<string> col = new MyCollection<string>();
var ienumeratort = col.Current; //Uses IEnumerator<T>
var ienumerator = (IEnumerator)col.Current; //uses IEnumerator
SynerCoder
  • 12,493
  • 4
  • 47
  • 78
  • 6
    More typical is to make the strong-typed property public, and only use explicit interface implementation for the `object`-type property. – Joe White Aug 07 '13 at 13:27
1

I think with C# 2.0 onwards, you have a very easy way of implementing iterator and compiler does a lot of heavy lifting behind the scene by creating state machine. It's worth looking into it. Having said that, in that case your implementation would look something below:

    public class MyCollection<T>
    {
        private T[] vector = new T[1000];
        private int actualIndex;

        public void Add(T elemento)
        {
            this.vector[vector.Length] = elemento;
        }

        public IEnumerable<T> CreateEnumerable()
        {
          for (int index = 0; index < vector.Length; index++)
          {
            yield return vector[(index + actualIndex)];
          }
       }
   }

I am not sure about the purpose of actualIndex though - but i hope you get the idea.

After proper initialization of MyCollection, below is snippet somewhat looks like from consumer perspective:

MyCollection<int> mycoll = new MyCollection<int>();
            foreach (var num in mycoll.CreateEnumerable())
            {
                Console.WriteLine(num);
            }
rahulaga-msft
  • 3,964
  • 6
  • 26
  • 44