获取 IEnumerable 的第一项和 return 其余项作为 IEnumerable,仅迭代一次

Get the first item of an IEnumerable and return the rest as IEnumerable, iterating through only once

我有一个可枚举对象,其中包含来自逐渐进入的服务调用的响应。

如何获取可枚举的第一个元素和return可枚举的延续?我无法使用迭代器方法,因为出现编译错误:

Iterators cannot have ref, in or out parameters.

我试过这个代码:

public IEnumerable<object> GetFirstAndRemainder(IEnumerable<object> enumerable, out object first)
{
      first = enumerable.Take(1).FirstOrDefault();
      return enumerable.Skip(1);  // Second interation - unexceptable
}


// This one has a compilation error: Iterators cannot have ref, in or out parameters
public IEnumerable<object> GetFirstAndRemainder2(IEnumerable<object> enumerable, out object first)
{
    var enumerator = enumerable.GetEnumerator();
    enumerator.MoveNext();
    first = enumerator.Current;
    while (enumerator.MoveNext())
    {
        yield return enumerator.Current;
    }
}

除了使用 out 参数外,您还可以使用 ValueTuple<T1, T2>(自 C# 7.0 起,已记录 here)到 return 两个元素:第一项IEnumerable<T>,其余为另一个 IEnumerable<T>

using System.Linq;

class Program {
    static void Main(string[] args) {
        (int first, IEnumerable<int> remainder) = GetFirstAndRemainder(Enumerable.Range(1, 5));
        // first = 1
        // remainder yields (2, 3, 4, 5)
    }

    // Returns the first item and the remainders as an IEnumerable
    static (T, IEnumerable<T>) GetFirstAndRemainder<T>(IEnumerable<T> sequence) {
        var enumerator = sequence.GetEnumerator();
        enumerator.MoveNext();
        return (enumerator.Current, enumerator.AsEnumerable());
    }
}

您还需要将 IEnumerator 转换为 IEnumerable,这是我使用扩展方法完成的:

static class Extensions {
    public static IEnumerable<T> AsEnumerable<T>(this IEnumerator<T> enumerator) {
        while (enumerator.MoveNext()) {
            yield return enumerator.Current;
        }
    }
}

请注意,根据您的要求,在 remainder 上迭代一次将耗尽它,即使它的类型为 IEnumerable<T>.