C# 对Count()等方法的连续调用是否重新计算IEnumerable<;T>;?

C# 对Count()等方法的连续调用是否重新计算IEnumerable<;T>;?,c#,ienumerable,C#,Ienumerable,我对IEnumerable有点困惑,它是延迟执行行为 假设我有以下IEnumerable: 我可以想到三种可能性: a) 将再次枚举集合 b) 将缓存第二次使用的结果(如延迟加载) c) 将取决于GetFoos()方法中实例化的下划线类型以及它如何实现IEnumerable接口 哪一个是正确的?此外,如果c是正确的,那么使用收益率返回创建的IEnumerable会发生什么情况?快速检查会给出.Count(此IEnumerable)扩展名(简化)的以下定义: 免责声明您不应该依赖于该实现,也不应该

我对IEnumerable有点困惑,它是延迟执行行为

假设我有以下
IEnumerable

我可以想到三种可能性:

a) 将再次枚举集合

b) 将缓存第二次使用的结果(如延迟加载)

c) 将取决于
GetFoos()
方法中实例化的下划线类型以及它如何实现IEnumerable接口

哪一个是正确的?此外,如果
c
是正确的,那么使用
收益率返回创建的IEnumerable会发生什么情况?

快速检查会给出
.Count(此IEnumerable)
扩展名(简化)的以下定义:

免责声明您不应该依赖于该实现,也不应该期望该实现总是以某种方式做一些事情

public static int Count<TSource>(this IEnumerable<TSource> source) {
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        while (e.MoveNext()) count++;
    }
    return count;
}

答案是(c)。这将取决于收集的实际执行情况。有些会重新枚举,有些不会,有些根本不会为
.Count()
枚举,有些会因多次尝试枚举而产生错误。第一个调用端口应该是:“如果源代码的类型实现了
ICollection
,则该实现用于获取元素的计数。否则…”因此,如果一个人没有意识到这一点,并且正在对收益率返回的方法进行大量操作,那么通过两次调用该方法,将导致速度缓慢,甚至可能产生副作用?即使实现了
ICollection
,它仍然取决于底层类型。Count属性仍然没有枚举是没有必要的。无法保证价值是正确的Cached@Guilherme1.副作用的例子更多的是为了演示。我想你永远不应该在迭代器中产生这样的副作用。2.我认为最好在需要时进行优化,避免过早优化。
int count = enumerable.Count();
count = enumerable.Count();
public static int Count<TSource>(this IEnumerable<TSource> source) {
    ICollection<TSource> collectionoft = source as ICollection<TSource>;
    if (collectionoft != null) return collectionoft.Count;
    ICollection collection = source as ICollection;
    if (collection != null) return collection.Count;
    int count = 0;
    using (IEnumerator<TSource> e = source.GetEnumerator()) {
        while (e.MoveNext()) count++;
    }
    return count;
}
private static IEnumerable<int> ConstantEnumerable()
{
    yield return 1;
    yield return 2;
    yield return 3;
}

private static int i = 0;
private static IEnumerable<int> ChangingEnumerable()
{
    if (i == 0)
    {
        yield return 1;
        i++;
    }
    else
    {
        yield return 2;
        yield return 3;
    }
}

public static void Main()
{
    var constant = ConstantEnumerable();
    var changing = ChangingEnumerable();
    Console.WriteLine("Constant: {0}, {1}", constant.Count(), constant.Count());  // 3, 3
    Console.WriteLine("Changing: {0}, {1}", changing.Count(), changing.Count()); // 1, 2
}