6

我正在寻找一个答案来质疑Get next N 个元素 from enumerable没有找到任何令人满意的东西并自己酿造。我想出的是

IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n, Func<IEnumerable<R>, T> action){
  IEnumerable<R> head;
  IEnumerable<R> tail = src;
  while (tail.Any())
  {
    head = tail.Take(n);
    tail = tail.Skip(n);
    yield return action(head);
  }
}

不过,我真正想要的是让 action 具有默认值t=>t,但我不知道如何将其设为默认参数。签名IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n, Func<IEnumerable<R>, T> action = t=>t)给出了语法错误。

我的问题是,我该怎么做?

我想这与将lambda 函数指定为默认参数但用于 C# 而不是 C++相同

作为旁注,我知道它在语法上没有任何区别,但是如果我切换Tand会更容易阅读R吗?

4

2 回答 2

13

默认值必须是常量,并且委托的唯一常量值是null引用。

我建议你改用重载。请注意,t => t这无论如何都是无效的,除非您知道存在从IEnumerable<R>to的转换T,而我在任何地方都看不到。

除了 lambda 表达式有效性问题之外,您还可以使用 null 合并运算符:

IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n,
                           Func<IEnumerable<R>, T> action = null)
{
    action = action ?? (t => t);
    ...
}

null...但这有点滥用它,您将无法判断ArgumentNullException.

编辑:另外,请注意,您的方法从根本上是有问题的 - 迭代块将多次评估原始序列(每个块一次)以跳过正确的数量。编写一个在返回之前急切读取每个块的方法可能会更好。我们在MoreLINQ中有一个类似的方法,称为Batch. 请注意,这Batch正是这里提到的重载 - 在这种情况下,t => t工作正常,因为重载的类型参数较少,所以我们知道身份转换是可以的。

于 2012-06-21T14:28:24.887 回答
2

C# 也是如此:创建重载。

IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n){
    return Chunk<T, R>(src, n, t => t);
}
于 2012-06-21T14:29:10.283 回答