我正在查看Batch方法的源代码,我已经看到了这个:
// Select is necessary so bucket contents are streamed too
yield return resultSelector(bucket.Select(x => x));
Run Code Online (Sandbox Code Playgroud)
有一条我不太明白的评论.我已经测试了这种方法而没有使用Select它并且运行良好.但似乎有些东西我不知道.我想不出任何必要的例子,那么Select(x => x)在这里使用的实际目的是什么?
以下是完整的源代码供参考:
private static IEnumerable<TResult> BatchImpl<TSource, TResult>(
this IEnumerable<TSource> source,
int size,
Func<IEnumerable<TSource>, TResult> resultSelector)
{
TSource[] bucket = null;
var count = 0;
foreach (var item in source)
{
if (bucket == null)
bucket = new TSource[size];
bucket[count++] = item;
// The bucket is fully buffered before it's yielded
if (count != size)
continue;
// Select is necessary so bucket contents are streamed too
yield return resultSelector(bucket.Select(x => x));
bucket = null;
count = 0;
}
// Return the last bucket with all remaining elements
if (bucket != null && count > 0)
yield return resultSelector(bucket.Take(count));
}
Run Code Online (Sandbox Code Playgroud)
总结评论中的内容,理论上这是多余的.在这种情况下,延迟执行无关紧要.在yield完全执行的时候已经完成了:bucket已经计算了内容,没有什么可以推迟的.
迭代器块行为也没有问题 - 每次我们回到这个实现时,bucket都会被重置并重新创建(bucket = null紧接在之后yield).即使有人将结果转换为数组类型并进行修改,我们也不在乎.
这种方法的一个优点似乎只是优雅:所有调用之间都存在类型一致性resultSelector.没有"冗余" Select,实际类型将在TSource[]大多数时间,并且IEnumerable<TSource>对于没有填充整体的尾随元素bucket.
但是,可以想象以下场景:
TSource[](例如,他们现在可以更有效地跳过元素,因为Skip没有针对数组进行优化)Count() % size == 0在他们的情况下直到,之后,会发生一个额外的元素弹出,导致最后一个元素yield被执行.而现在演员TSource[]将失败.
因此,取决于元素的数量,并且size该方法在其结果类型方面表现不一致(传递给给定的回调).可以想象其他复杂的情况,这种不一致可能会导致麻烦,例如某些ORM,根据实际类型,将对象序列化到不同的表中.在这种情况下,数据片段最终会出现在不同的表格中.
这些场景当然都是基于其他一些错误,并没有证明没有Select实施是错误的.然而更友好的使用Select,从某种意义上说,这减少了这样的不幸场景的数量降到最低.
| 归档时间: |
|
| 查看次数: |
248 次 |
| 最近记录: |