I want to iterate over the values of my custom collection using C#.
I created a collection named MyLinkedList to represent a custom linked list like this
public class MyLinkedList<T> : IEnumerable<T?> where T : IEquatable<T?>
{
// other methods are removed for simplicity.
IEnumerator<T?> IEnumerable<T?>.GetEnumerator()
=> new MyLinkedListNodeEnumerator<T>(_root);
public IEnumerator GetEnumerator()
=> new MyLinkedListNodeEnumerator<T>(_root);
}
I implemented the IEnumerable<T?> interface, so I can use foreach loop to iterate over the values in my custom collection. Here is the implementation of MyLinkedListNodeEnumerator
public class MyLinkedListNodeEnumerator<T>(MyLinkedListNode<T>? root)
: IEnumerator<T?> where T : IEquatable<T?>
{
private readonly MyLinkedListNode<T>? _root = root;
private MyLinkedListNode<T>? _current = root;
public object? Current
{
get
{
var current = _current;
_current = _current!.Next;
return current;
}
}
T? IEnumerator<T?>.Current
{
get
{
var current = _current;
_current = _current!.Next;
return current!.Data;
}
}
public void Dispose()
{
}
public bool MoveNext()
=> _current?.Next != null;
public void Reset()
{
_current = _root;
}
}
Here is a use case example,
var list = new MyLinkedList<int>();
list.InsertFirst(10);
list.InsertNext(20);
list.InsertNext(30);
When I loop over the Enumerator object, I am expecting that each item to be of int type since that is the generic type to create the list. So the foreach is using IEnumerator GetEnumerator() not IEnumerable<T?>.GetEnumerator().
foreach(var item in list)
{
// here item is an object of a type MyLinkedListNode<int>
// not int as I am expecting.
}
How do I ensure that foreach will use IEnumerable<T?>.GetEnumerator() so I can iterate over int values instead?
Without knowing the specifics of your
MyLinkedListNode:Note that
Currentis idempotent and should not modify the enumerator. The only way to move the enumerator forward is usingMoveNext. In the initial state, the enumerator is supposed to start before the first element which is why_currentstarts atnull. Also, accessingCurrentwithout a previous successfulMoveNextcall is not defined.In order for your enumerator to be generic by default, you should swap around your implementation of
IEnumerable<T>: