private IEnumerable<string> Tables
{
    get
    {
        yield return "Foo";
        yield return "Bar";
    }
}

假设我想要迭代这些并写一些类似于processing #n of #m的东西。

有没有一种方法可以让我在不进行主迭代的情况下求出m的值?

我希望我讲清楚了。


当前回答

我发现最好的方法是把它转换成一个列表。

IEnumerable<T> enumList = ReturnFromSomeFunction();

int count = new List<T>(enumList).Count;

其他回答

它可能不会产生最好的性能,但你可以使用LINQ来计算IEnumerable中的元素:

public int GetEnumerableCount(IEnumerable Enumerable)
{
    return (from object Item in Enumerable
            select Item).Count();
}

IEnumerable<T>上的System.Linq.Enumerable.Count扩展方法有以下实现:

ICollection<T> c = source as ICollection<TSource>;
if (c != null)
    return c.Count;

int result = 0;
using (IEnumerator<T> enumerator = source.GetEnumerator())
{
    while (enumerator.MoveNext())
        result++;
}
return result;

因此,它尝试强制转换为具有Count属性的ICollection<T>,并尽可能使用该属性。否则它会迭代。

因此,最好的方法是在IEnumerable<T>对象上使用Count()扩展方法,因为这样可以获得最好的性能。

这里有一个关于惰性求值和延迟执行的很好的讨论。基本上你必须物化这个列表才能得到这个值。

我的一个朋友有一系列的博客文章来说明为什么你不能这样做。他创建了一个返回IEnumerable的函数,每次迭代都会返回下一个质数,一直到ulong。MaxValue,下一项直到您请求它时才计算。一个简单的问题:返回了多少项?

以下是一些帖子,但它们有点长:

Beyond Loops(提供一个在其他帖子中使用的初始EnumerableUtility类) 迭代应用(初始实现) 疯狂的扩展方法:ToLazyList(性能优化)

你可以使用System.Linq。

using System;
using System.Collections.Generic;
using System.Linq;

public class Test
{
    private IEnumerable<string> Tables
    {
        get {
             yield return "Foo";
             yield return "Bar";
         }
    }

    static void Main()
    {
        var x = new Test();
        Console.WriteLine(x.Tables.Count());
    }
}

你会得到结果'2'。