gpt4 book ai didi

c# - IEnumerable.Count 在哪些情况下进行了优化?

转载 作者:可可西里 更新时间:2023-11-01 07:57:03 32 4
gpt4 key购买 nike

使用 reflector我注意到 System.Linq.Enumerable.Count 方法中有一个条件可以针对 IEnumerable<T> 的情况对其进行优化。 passed 实际上是一个 ICollection<T> .如果转换成功,Count 方法不需要遍历每个元素,而是可以调用 ICollection 的 Count 方法。

基于此,我开始认为 IEnumerable<T>可以像集合的只读 View 一样使用,而不会出现我最初基于 IEnumerable<T> 的 API 预期的性能损失

我感兴趣的是是否优化了Count IEnumerable<T> 时仍然成立是 Select 的结果关于 ICollection 的声明,但根据反射(reflect)的代码,这种情况并未优化,需要对所有元素进行迭代。

你从reflector得出同样的结论吗?缺乏这种优化背后的原因可能是什么?我似乎在这个常见的操作中浪费了很多时间。规范是否要求计算每个元素,即使不这样做也可以确定计数?

最佳答案

Select 的结果并不重要被懒惰地评估。 Count始终等于原始集合的计数,因此可以通过从 Select 返回特定对象来直接检索它可用于对 Count 进行短路评估方法。

不可能优化 Count() 的评估的原因Select 返回值的方法从具有确定计数的东西(如 List<T> )调用是因为它可以改变程序的含义。

selector函数传递给 Select允许方法有副作用,并且它的副作用需要以预定的顺序确定地发生。

假设:

new[]{1,2,3}.Select(i => { Console.WriteLine(i); return 0; }).Count();

文档需要打印这段代码

1
2
3

即使从一开始就确实知道计数并且可以对其进行优化,优化也会改变程序的行为。这就是为什么您无论如何都无法避免枚举集合的原因。这正是编译器优化在纯函数式语言中更容易的原因之一。


更新:显然,尚不清楚是否完全有可能实现SelectCount这样Select关于 ICollection<T>仍将被延迟评估,但 Count()将在不枚举集合的情况下在 O(1) 中进行评估。我将在不更改任何方法的接口(interface)的情况下执行此操作。 ICollection<T> 已经做了类似的事情:

private interface IDirectlyCountable {
int Count {get;}
}
private class SelectICollectionIterator<TSource,TResult> : IEnumerable<T>, IDirectlyCountable {
ICollection<TSource> sequence;
Func<TSource,TResult> selector;
public SelectICollectionIterator(ICollection<TSource> source, Func<TSource,TResult> selector) {
this.sequence = source;
this.selector = selector;
}
public int Count { get { return sequence.Count; } }
// ... GetEnumerator ...
}
public static IEnumerable<TResult> Select<TSource,TResult>(this IEnumerable<TSource> source, Func<TSource,TResult> selector) {
// ... error handling omitted for brevity ...
if (source is ICollection<TSource>)
return new SelectICollectionIterator<TSource,TResult>((ICollection<TSource>)source, selector);
// ... rest of the method ...
}
public static int Count<T>(this IEnumerable<T> source) {
// ...
ICollection<T> collection = source as ICollection<T>;
if (collection != null) return collection.Count;
IDirectlyCountable countableSequence = source as IDirectlyCountable;
if (countableSequence != null) return countableSequence.Count;
// ... enumerate and count the sequence ...
}

这仍然会评估 Count懒洋洋。如果您更改基础集合,计数将更改并且序列不会被缓存。唯一的区别是不会在 selector 中产生副作用。代表。

关于c# - IEnumerable<T>.Count 在哪些情况下进行了优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2180799/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com