I have built a linked list in C# from scratch and have solid unit test coverage to make sure it works.
To easily compare linked lists with lots of values I'm "enumerating" the values by hand using the standard while CurrentNode.Next != null, advance technique and storing those values in a C# List or array.
I want to implement IEnumerable on my custom LinkedList class and not rely on getting the enumerator from a private backing collection.
Here's the code of my LinkedList class. I feel like I'm overlooking something simple because the enumerator should just be an object you obtain from the collection class that provides a starting point and a next method as far as I can tell. I just can't get it to work in a generic manner.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CSharpLibrary.DataStructures.LinkedLists
{
public class LinkedList<T> : IEnumerable<T>
{
public Node<T> First { get; private set; }
public Node<T> Current { get; set; }
public LinkedList(T initialValue)
{
First = new Node<T>(initialValue);
}
public void AddNodeToEnd(T value)
{
Node<T> last = GetLastNode();
last.Next = new Node<T>(value);
}
public Node<T> GetLastNode()
{
Node<T> last = First;
Node<T> current = First;
while (current.Next != null)
{
last = current.Next;
current = current.Next;
}
return current;
}
public void Reset()
{
Current = First;
}
public IEnumerator<T> GetEnumerator()
{
throw new NotImplementedException();
}
IEnumerator IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
}
}
IEnumerable interface is a generic interface which allows looping over generic or non-generic lists. IEnumerable interface also works with linq query expression. IEnumerable interface Returns an enumerator that iterates through the collection.
IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.
What you can do is use the Add extension method to create a new IEnumerable<T> with the added value. var items = new string[]{"foo"}; var temp = items; items = items. Add("bar");
To add to Bradley's answer, note that methods returning IEnumerator<T>
also support the yield
keyword:
public class LinkedList<T> : IEnumerable<T>
{
...
// this will automagically create the
// appropriate class for you
public IEnumerator<T> GetEnumerator()
{
Node<T> current = First;
while (current != null)
{
yield return current.Value;
current = current.Next;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
// this will invoke the public generic
// version, so there is no recursion
return this.GetEnumerator();
}
}
You should, however, remove Current
and Reset()
from the parent class, they don't belong there. And your GetLastNode()
method has two duplicate variables, you can remove one of them.
Since you have created a custom collection, you won't be able to just use an existing IEnumerator
implementation. You'll need to create one:
public class LinkedListEnumerator<T> : IEnumerator<T>
{
public LinkedListEnumerator(LinkedList<T> collection)
{
}
...
}
I'm passing the collection to be enumerated into the constructor. Other ways could work but that seemed the easiest way to get it there. Now your IEnumerable<T>
implementation is:
public IEnumerator<T> GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}
Actual IEnumerator
implementation left as an exercise.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With