user9623401
user9623401

Reputation:

Implement own collection in C# but need to modify the IEnumerable?

I found a great article illustrate IEnumerable and IEnumerator

https://programmingwithmosh.com/csharp/ienumerable-and-ienumerator/

below is the source code:

public class List : IEnumerable
{
    private object[] _objects;

    public List()
    {
        _objects = new object[100];
    }

    public void Add(object obj)
    {
        _objects[_objects.Count] = obj;
    }

    public IEnumerator GetEnumerator()
    {
        return new ListEnumerator();     //region 1
    } 

    private class ListEnumerator : IEnumerator 
    {
       private int _currentIndex = -1;
       public bool MoveNext()
       {
          _currentIndex++;
           return (_currentIndex < _objects.Count); 
       }
       public object Current
       {
         ...
       }
       public void Reset()
       {
           _currentIndex = -1;
       }
    }
}

I found some mistakes in this article, probably some typos such as _objects.Count should be _objects.Length but one fundamental problem is: How can you get access _objects in ListEnumerator? So I guess I need to pass 'this' in region 1

 public IEnumerator GetEnumerator()
 {
    return new ListEnumerator(this);
 } 

and modify ListEnumerator as:

private class ListEnumerator : IEnumerator 
{
   private int _currentIndex = -1;
   IEnumerable aggregate = null;
   public ListEnumerator(IEnumerable param)
   {
      aggregate  = param
   }

   public bool MoveNext()
   {
      _currentIndex++; 
      return (_currentIndex < aggregate.Count);   //important region
   }
   public object Current
   {
      //don't worry about the boundary check/exceptions
     get
     {
         return aggregate[_currentIndex];  //important region
     }
   }
...
}

In order to do this, IEnumerable also needs to be like

interface IEnumerable 
{
   IEnumerator GetEnumerator();
   int Count{get;}
   object this[int itemIndex]{set;get;}
}

but we all know IEnumerable only have one method GetEnumerator() that needs to be implemented. So how can we do this, can anybody modify the code to make it work?

Upvotes: 2

Views: 84

Answers (1)

Chetan
Chetan

Reputation: 6911

There is a problem with the code of the article which you are referring.

_objects is a private member of class List so it can not be accessed outside of the class, even from the innterclass of List.

Even if you make _objects public, it can not be accessed without creating an object of List class.

Also there is no way IEnumerable interface can be modified.

I would suggest following two approaches.

Approach 1

Change ListEnumerator class constructor to accept an an object of List class

private class ListEnumerator : IEnumerator 
{
    private List _list;
    public ListEnumerator(List list)
    {
        this._list = list;
    }
    private int _currentIndex = -1; 

    public bool MoveNext()
    {
        _currentIndex++;

        return (_currentIndex < this._list._objects.Length); 
    }

    public object Current
    { 
        get
        {
            try
            {
                return this._list._objects[_currentIndex];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }

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

You also need to remove private from the declaration of _objects in List class. And pass this to ListEnumerator constructor.

public class List : IEnumerable
{
    object[] _objects;

    public List()
    {
        _objects = new object[100];
    }
    //Other code of List class.

    public IEnumerator GetEnumerator()
    {
       return new ListEnumerator(this);
    }
}

Approach 2

Change ListEnumerator class constructor to accept an array of objects.

private class ListEnumerator : IEnumerator 
{
    private object[] _objects;
    public ListEnumerator(object[] objects)
    {
        this._objects = objects;
    }

    private int _currentIndex = -1; 

    public bool MoveNext()
    {
        _currentIndex++;

        return (_currentIndex < this._objects.Length); 
    }

    public object Current
    { 
        get
        {
            try
            {
                return this._objects[_currentIndex];
            }
            catch (IndexOutOfRangeException)
            {
                throw new InvalidOperationException();
            }
        }
    }

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

And use it as following in List class.

public IEnumerator GetEnumerator()
{
   return new ListEnumerator(this._objects);
} 

Upvotes: 1

Related Questions