我正在寻找一个问题的问题Get next N elements 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);
}
}
我真的想要的是,操作的默认值为t=>t
,但我无法弄清楚如何将其作为默认参数。签名IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n, Func<IEnumerable<R>, T> action = t=>t)
会出现语法错误。
我的问题是,我该怎么做?
我认为这与Specifying a lambda function as default argument相同,但对于C#而不是C ++
作为旁注,我知道它没有任何语法差异,但如果我切换T
和R
会更容易阅读吗?
答案 0 :(得分:10)
默认值必须是常量,委托的唯一常量值是null
引用。
我建议您使用重载。请注意,t => t
无论如何都不会有效,除非您知道从IEnumerable<R>
到T
的转换,我在任何地方都看不到。
除了lambda表达式有效性问题,你可以使用空合并运算符:
IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n,
Func<IEnumerable<R>, T> action = null)
{
action = action ?? (t => t);
...
}
...但这会有点滥用它,你无法判断来自认为他们传递非传递者的null
实际上是 -null值,并且您希望提高ArgumentNullException
。
编辑:此外,请注意您的方法从根本上是有问题的 - 迭代块将多次评估原始序列(每个块一次)以跳过正确的数量。编写一个热切地读取每个块的方法可能会更好。我们在MoreLINQ中使用了类似的方法,称为Batch
。请注意,Batch
完全具有此处提到的重载 - 在这种情况下,t => t
有效,因为重载具有较少的类型参数,因此我们知道身份转换是可以的。
答案 1 :(得分:2)
C#也是一样:创建一个重载。
IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n){
return Chunk<T, R>(src, n, t => t);
}