计算IEnumerable(非泛型)的数量

55

有谁能为我提供一个 IEnumerableCount 扩展方法(非泛型接口)?

我知道它在 LINQ 中不受支持,但该如何手动编写呢?

4个回答

60
yourEnumerable.Cast<object>().Count()

针对性能的评论:

我认为这是过早优化的一个好例子,但以下是代码:

static class EnumerableExtensions
{
    public static int Count(this IEnumerable source)
    {
        int res = 0;

        foreach (var item in source)
            res++;

        return res;
    }
}

4
@Daniel检查ICollection的答案更好,就这样说吧... - Marc Gravell
1
@Marc 第一个.Cast<object>().Count()已经进行了检查(泛型和非泛型)。但是,是的,第二种解决方案可以通过检查来改进。 - Lasse Espeholt
把它强制转换为通用的IEnumerable<T>版本有什么意义?这将违反使用非通用IEnumerable的原因-正是为了当您不知道/不关心元素类型时使用。因此,您将无法对元素类型进行任何编译时转换,因为它们是未知的(如果它们已知,则首先使用的IEnumerable应该是通用的)。 - Veverke
如果最终所需的全部是获取元素的总数,那么对象类型可能不应该是IEnumerable,而应该是ICollection。泛型和非泛型版本都提供了Count属性。 - Veverke
我同意编辑后答案中的“过早优化”论点。 - Fabio Milheiro

50

最简单的形式是:

public static int Count(this IEnumerable source)
{
    int c = 0;
    using (var e = source.GetEnumerator())
    {
        while (e.MoveNext())
            c++;
    }
    return c;
}

你可以通过查询 ICollection 来进一步完善此操作:

public static int Count(this IEnumerable source)
{
    var col = source as ICollection;
    if (col != null)
        return col.Count;

    int c = 0;
    using (var e = source.GetEnumerator())
    {
        while (e.MoveNext())
            c++;
    }
    return c;
}

更新

正如Gerard在评论中指出的那样,非泛型的 IEnumerable 并不继承 IDisposable,因此普通的 using 语句将无法工作。如果可能的话,尝试释放这些枚举器仍然很重要 - 迭代器方法实现了 IEnumerable,因此可能会通过间接方式传递给此 Count 方法。在内部,该迭代器方法将依赖于对 Dispose 的调用来触发自己的 try/finallyusing 语句。

为了让其他情况下更容易实现,你可以创建自己版本的 using 语句,它在编译时要求较少:

public static void DynamicUsing(object resource, Action action)
{
    try
    {
        action();
    }
    finally
    {
        IDisposable d = resource as IDisposable;
        if (d != null)
            d.Dispose();
    }
}

更新后的Count方法如下:

public static int Count(this IEnumerable source) 
{
    var col = source as ICollection; 
    if (col != null)
        return col.Count; 

    int c = 0;
    var e = source.GetEnumerator();
    DynamicUsing(e, () =>
    {
        while (e.MoveNext())
            c++;
    });

    return c;
}

1
查询 IList 或查询其基接口 ICollection - Joe
2
我尝试了这个扩展,using 对于 System.Collections.IEnumerable 报编译错误。我将代码更改为 Count<T>(this IEnumerable<T> source) 可以通过编译。 - Gerard

4
不同类型的IEnumerable具有不同的最佳方法来确定计数。不幸的是,没有通用的方法来知道哪种方法对于任何给定的IEnumerable最好,甚至没有任何标准方式可以让IEmumerable指示以下哪种技术最好:
1. 直接询问对象。支持IEnumerable的某些类型的对象,例如Array、List和Collection,具有可以直接报告其元素数量的属性。 2. 枚举所有项目,丢弃它们,并计算枚举的项目数。 3. 将所有项枚举到列表中,然后如果需要再次使用枚举,则使用该列表。
以上每种方法在不同情况下都是最优的。

4

我认为在第一次选择表示元素序列的类型时,应该选择ICollection而不是IEnumerable

ICollectionICollection<T>都提供一个Count属性,此外每个ICollection也实现了IEnumerable接口。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接