假设我有IEnumerable<T>
,我想获取第一个元素并将其余元素传递给其他代码。我可以使用Take(n)
获取第一个 n 元素,但是如何在不导致枚举重新启动的情况下访问其余元素?
例如,假设我有一个方法ReadRecords
,它接受CSV文件中的记录为IEnumerable<string>
。现在假设在该方法中,我想读取第一条记录(标题),然后将剩余的记录传递给ReadDataRecords
方法,该方法也需要IEnumerable<string>
。像这样:
void ReadCsv(IEnumerable<string> records)
{
var headerRecord = records.Take(1);
var dataRecords = ???
ReadDataRecords(dataRecords);
}
void ReadDataRecords(IEnumerable<string> records)
{
// ...
}
如果我准备重新开始枚举,那么我可以使用dataRecords = records.Skip(1)
。但是,我不想重新启动它 - 事实上,它可能无法重新启动。
那么,有没有办法获取第一个记录,然后是剩余的记录(除了将所有值读入新的集合并重新枚举它们)?
答案 0 :(得分:14)
这是一个有趣的问题,我认为你可以使用这样的解决方法,而不是使用LINQ
获取枚举器并使用它:
private void ReadCsv(IEnumerable<string> records)
{
var enumerator = records.GetEnumerator();
enumerator.MoveNext();
var headerRecord = enumerator.Current;
var dataRecords = GetRemainingRecords(enumerator);
}
public IEnumerable<string> GetRemainingRecords(IEnumerator<string> enumerator)
{
while (enumerator.MoveNext())
{
if (enumerator.Current != null)
yield return enumerator.Current;
}
}
更新:根据您的评论,这里有更广泛的方式:
public static class CustomEnumerator
{
private static int _counter = 0;
private static IEnumerator enumerator;
public static IEnumerable<T> GetRecords<T>(this IEnumerable<T> source)
{
if (enumerator == null) enumerator = source.GetEnumerator();
if (_counter == 0)
{
enumerator.MoveNext();
_counter++;
yield return (T)enumerator.Current;
}
else
{
while (enumerator.MoveNext())
{
yield return (T)enumerator.Current;
}
_counter = 0;
enumerator = null;
}
}
}
用法:
private static void ReadCsv(IEnumerable<string> records)
{
var headerRecord = records.GetRecords();
var dataRecords = records.GetRecords();
}
答案 1 :(得分:3)
是的,使用IEnumerable中的IEnumerator
,您可以保持方法调用的位置;
一个简单的例子;
public class Program
{
static void Main(string[] args)
{
int[] arr = new [] {1, 2, 3};
IEnumerator enumerator = arr.GetEnumerator();
enumerator.MoveNext();
Console.WriteLine(enumerator.Current);
DoRest(enumerator);
}
static void DoRest(IEnumerator enumerator)
{
while (enumerator.MoveNext())
Console.WriteLine(enumerator.Current);
}
}