Reputation:
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
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