Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement IEnumerable<T> in C# on linked list built from scratch

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();
        }
    }
}
like image 970
Josh R Avatar asked Mar 16 '17 21:03

Josh R


People also ask

What is IEnumerable T interface in C#?

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.

What is IEnumerable <>?

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.

How do you add an IEnumerable?

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");


2 Answers

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.

like image 181
Groo Avatar answered Oct 09 '22 20:10

Groo


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.

like image 37
BradleyDotNET Avatar answered Oct 09 '22 18:10

BradleyDotNET