I was looking for an anwer to question Get next N elements from enumerable didn’t find any satisfying and brewed my own. What I came up with was
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);
}
}
What I would really like though, is to have action have a default of t=>t, but I can’t figure out how to make that a default argument. The signature IEnumerable<T> Chunk<T, R>(IEnumerable<R> src, int n, Func<IEnumerable<R>, T> action = t=>t) gives a syntax error.
My question is, how do I do this?
I suppose this is identical to Specifying a lambda function as default argument but for C# instead of C++
As a side note, I know it doesn’t make any syntactical difference, but would it be easier to read if I switched T and R?
Default values have to be constants, and the only constant value for a delegate is a
nullreference.I suggest you use overloading instead. Note that
t => twouldn’t be valid anyway, unless you know that there’s a conversion fromIEnumerable<R>toT, which I don’t see anywhere.Aside from the lambda expression validity problem, you could use the null coalescing operator:
… but that would be sort of abusing it, and you wouldn’t be able to tell whether the
nullwas actually from a caller who thought they were passing a non-null value, and would prefer you to raise anArgumentNullException.EDIT: Additionally, note that your method is fundamentally problematic – iterating over the chunks will evaluate the original sequence several times (once per chunk) in order to skip the right amount. It would probably be better to write a method which eagerly read each chunk before returning it. We have a similar method in MoreLINQ, called
Batch. Note thatBatchhas exactly the overload mentioned here – and in this case, thet => tworks, because the overload has fewer type parameters, so we know the identity conversion is okay.