2

I am implementing ICollection< T > and there are problems doing enumerator implementation.

I understand that IEnumerator< T > has to implement IEnumerator for back-compatibility (.NET 1.0)

But If i am implementing IEnumerator< T >, then there are 2 Current Properties.

I have 2 questions:

  1. What should be their relation ? Is following code correct ?

    T IEnumerator<T>.Current 
    { 
        get 
        {
            if (_cursor < 0 || _cursor >= _array.Length)
                throw new InvalidOperationException("Iterator position invalid");
            else 
                return _array[_cursor];
        } 
    }
    
    
    object IEnumerator.Current
    {
        get
        {
            return IEnumerator<T>.Current;
        }
    }
    

I get this error: An object reference is required for the non-static field, method, or property 'System.Collections.Generic.IEnumerator.Current.get'

(2). Why IEnumerator< T > has to implement IDisposable. Dispose is for unmanaged resources, but in what scenario in-general would Enumerator use unmanaged resources ?

Munish Goyal
  • 1,379
  • 4
  • 27
  • 49
  • The second question is a duplicate of this [one](http://stackoverflow.com/questions/232558/why-ienumerator-of-t-inherts-from-idisposable-but-non-generic-ienumerator-does-n). – ba__friend May 30 '11 at 09:57

2 Answers2

3

There are several cases where it's useful that IEnumerator<T> inherits from IDisposable.

For example take File.ReadLines() which needs to keep open a FileStream, which is an unmanaged resource.

Or if you think about an iterator using the yield syntax you need IDisposable to make finally clauses work correctly:

IEnumerator<int> MyIt()
{
  try
  {
    yield return 1;
  }
  finally
  {
    //Do Something
  }
}

Typically you'd implement Current like this:

T Current//Implicit interface implementation
{
  get
  {
    return something;
  }
}

object IEnumerator.Current{get{return Current;}}

Your original code doesn't work since you try to get a static property on the interface itself. You probably wanted to to ((IEnumerator<T>)this).Current. But if you implement T Current{...} implicitly you don't need that cast at all.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • I did object IEnumerator.Current { get { return (IEnumerator)this.Current; } } but it has compile error again saying definition of Current could not be found. – Munish Goyal May 30 '11 at 10:00
  • 1
    `.` has higher precedence than casting. Notice the extra parentheses in my code. – CodesInChaos May 30 '11 at 10:01
  • works now. 1 question on Dispose. Compiler needs Dispose to be public Dispose, why ? Interface methods need not have any access modifier , right ? For MoveNext, Reset I had to remove public because complier complained so. – Munish Goyal May 30 '11 at 10:04
  • If you make it a normal method that implicitly implements an interface you need to make it public. If you're implementing an interface explicitly you can't specify a visibility manually, since the interface already determines the visibility. – CodesInChaos May 30 '11 at 12:04
1
  1. return ((IEnumerator<T>)this).Current;

  2. Dispose() is used to tell enumerator that it is not needed anymore (so you can, for example, disconnect from some data source, or do something else).

max
  • 33,369
  • 7
  • 73
  • 84