如果你想要获取一个IEnumerator并得到代表序列其余部分的IEnumerable,那么字面上来说,你需要进行一些魔法才能实现。
这是因为通常情况下,可枚举对象可以被多次枚举,而枚举器只能枚举一次,它只是其中的一个“多次”本身。
首先,你可以尝试找出你正在处理的集合类型,并在原始枚举器之上返回一个适当的枚举器。你所需要的原因就是这个。
或者...你可以将枚举器的剩余部分缓存到一个新的集合中并返回它。当然,这将消耗你原来的枚举器,无论它是什么,可能会在时间或内存方面很昂贵。
或者...你可以做一些其他人建议的事情,不实际返回枚举器,而是使用可枚举类的Skip和Take方法返回你想要的内容。这将返回一个新的可枚举对象,每次枚举时它都将枚举原始可枚举对象,跳过前两个项并生成其余项。
让我重新措辞一下最后一段。如果你不试图将IEnumerator的剩余部分作为新的可枚举对象返回,而是直接处理原始集合,那么处理起来就容易得多。
下面是一些缓存元素的代码。它的好处是,如果你从生成的可枚举对象中产生了2个或更多的枚举器(甚至只有1个),然后让可枚举对象超出范围,当枚举器开始移动元素时,它将允许垃圾收集器开始收集已经传递的元素。
换句话说,如果你这样做:
var enumerable = enumerator.Remaining();
var enumerator1 = enumerable.GetEnumerator();
var enumerator2 = enumerable.GetEnumerator();
enumerator1.MoveNext();
enumerator2.MoveNext();
<
of the enumerable is no longer needed (there's no way to get to it)
it can be garbage collected.
当然,如果您保留可枚举对象并枚举其中的所有元素,它将生成原始可枚举对象中所有元素的内存副本,这可能是代价高昂的。无论如何,以下是代码。它不是线程安全的:
using System;
using System.Collections.Generic;
using System.Collections;
namespace SO2829956
{
public class EnumeratorEnumerable<T> : IEnumerable<T>
{
private class Node
{
public T Value;
public Node Next;
}
private class Enumerator : IEnumerator<T>
{
private IEnumerator<T> _Enumerator;
private Node _Current;
public Enumerator(IEnumerator<T> enumerator, Node headElement)
{
_Enumerator = enumerator;
_Current = headElement;
}
public T Current
{
get { return _Current.Value; }
}
public void Dispose()
{
_Enumerator.Dispose();
}
object IEnumerator.Current
{
get { return Current; }
}
public bool MoveNext()
{
if (_Current.Next != null)
{
_Current = _Current.Next;
return true;
}
else if (_Enumerator.MoveNext())
{
_Current.Next = new Node
{
Value = _Enumerator.Current
};
_Current = _Current.Next;
return true;
}
else
{
_Enumerator.Dispose();
return false;
}
}
public void Reset()
{
throw new NotImplementedException();
}
}
private IEnumerator<T> _Enumerator;
private Node _FirstElement;
public EnumeratorEnumerable(IEnumerator<T> enumerator)
{
_Enumerator = enumerator;
_FirstElement = new Node
{
Next = null,
Value = enumerator.Current
};
}
public IEnumerator<T> GetEnumerator()
{
return new Enumerator(_Enumerator, _FirstElement);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
public static class EnumeratorExtensions
{
public static IEnumerable<T> Remaining<T>(
this IEnumerator<T> enumerator)
{
return new EnumeratorEnumerable<T>(enumerator);
}
}
class Program
{
static void Main(string[] args)
{
List<int> values = new List<int> { 1, 2, 3, 4, 5 };
IEnumerator<int> enumerator = values.GetEnumerator();
enumerator.MoveNext();
enumerator.MoveNext();
var enumerable = enumerator.Remaining();
foreach (var i in enumerable)
Console.Out.WriteLine(i);
foreach (var i in enumerable)
Console.Out.WriteLine(i);
}
}
}
运行该程序的输出结果是:
3
4
5
3
4
5
Clone
方法。这可能会帮助你。您可以实现一个EnumerableEx<T>类,它包装了一个IEnumerable<T>并支持克隆。 - John Källénrest = sequence.Skip(2)
会复制你的例子,但不具有普适性... - jball