在从头构建的链表上用 C# 实现 IEnumerable<T>
Implement IEnumerable<T> in C# on linked list built from scratch
我从头开始用 C# 构建了一个链表,并且有可靠的单元测试覆盖率以确保它有效。
为了轻松比较具有大量值的链表,我使用标准手动 "enumerating" 值,而 CurrentNode.Next != null,高级技术并将这些值存储在 C# 列表中或数组。
我想在我的自定义 LinkedList class 上实现 IEnumerable,而不是依赖于从私有后备集合中获取枚举器。
这是我的 LinkedList class 的代码。我觉得我忽略了一些简单的事情,因为枚举器应该只是您从集合 class 中获得的一个对象,据我所知,它提供了一个起点和一个 next 方法。我只是无法让它以通用方式工作。
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();
}
}
}
由于您已经创建了自定义集合,因此您将不能只使用现有的 IEnumerator
实现。您需要创建一个:
public class LinkedListEnumerator<T> : IEnumerator<T>
{
public LinkedListEnumerator(LinkedList<T> collection)
{
}
...
}
我正在将要枚举的集合传递给构造函数。其他方法也可行,但这似乎是最简单的方法。现在您的 IEnumerable<T>
实现是:
public IEnumerator<T> GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}
实际 IEnumerator
实施留作练习。
要添加到 Bradley 的答案中,请注意返回 IEnumerator<T>
的方法也支持 yield
关键字:
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();
}
}
但是,您应该从父级 class 中删除 Current
和 Reset()
,它们不属于那里。并且您的 GetLastNode()
方法有两个重复变量,您可以删除其中一个。
我从头开始用 C# 构建了一个链表,并且有可靠的单元测试覆盖率以确保它有效。
为了轻松比较具有大量值的链表,我使用标准手动 "enumerating" 值,而 CurrentNode.Next != null,高级技术并将这些值存储在 C# 列表中或数组。
我想在我的自定义 LinkedList class 上实现 IEnumerable,而不是依赖于从私有后备集合中获取枚举器。
这是我的 LinkedList class 的代码。我觉得我忽略了一些简单的事情,因为枚举器应该只是您从集合 class 中获得的一个对象,据我所知,它提供了一个起点和一个 next 方法。我只是无法让它以通用方式工作。
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();
}
}
}
由于您已经创建了自定义集合,因此您将不能只使用现有的 IEnumerator
实现。您需要创建一个:
public class LinkedListEnumerator<T> : IEnumerator<T>
{
public LinkedListEnumerator(LinkedList<T> collection)
{
}
...
}
我正在将要枚举的集合传递给构造函数。其他方法也可行,但这似乎是最简单的方法。现在您的 IEnumerable<T>
实现是:
public IEnumerator<T> GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new LinkedListEnumerator<T>(this);
}
实际 IEnumerator
实施留作练习。
要添加到 Bradley 的答案中,请注意返回 IEnumerator<T>
的方法也支持 yield
关键字:
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();
}
}
但是,您应该从父级 class 中删除 Current
和 Reset()
,它们不属于那里。并且您的 GetLastNode()
方法有两个重复变量,您可以删除其中一个。