web-dev-qa-db-ja.com

IEnumerableのカウントの計算(非ジェネリック)

誰でもCountIEnumerable拡張メソッド(非汎用インターフェース)で私を助けることができます。

LINQではサポートされていませんが、手動で記述する方法は知っていますか?

46
Homam

最も単純な形式は次のとおりです。

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がコメントで指摘しているように、非汎用IEnumerableIDisposableを継承しないため、通常のusingステートメントは機能しません。可能であれば、そのような列挙子の破棄を試みることはおそらく重要です。イテレータメソッドはIEnumerableを実装するため、このCountメソッドに間接的に渡すことができます。内部的には、そのイテレータメソッドはDisposeへの呼び出しに依存して、独自のtry/finallyおよびusingステートメントをトリガーします。

他の状況でもこれを簡単にするために、コンパイル時に煩わしくない独自のバージョンの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;
}
42
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;
    }
}
47
Lasse Espeholt

IEnumerableの種類によって、カウントを決定するための最適な方法が異なります。残念ながら、どのメソッドが特定のIEnumerableに最適であるかを知るための汎用的な手段はなく、IEmumerableが次のテクニックのどれが最適であるかを示す標準的な手段すらありません。

  1. オブジェクトに直接尋ねるだけです。 Array、List、Collectionなど、IEnumerableをサポートする一部のタイプのオブジェクトには、その中の要素の数を直接報告できるプロパティがあります。
  2. すべてのアイテムを列挙して破棄し、列挙されたアイテムの数をカウントします。
  3. すべてのアイテムをリストに列挙し、列挙を再度使用する必要がある場合はリストを使用します。

上記のそれぞれは、異なる場合に最適です。

4
supercat

要素のシーケンスを表すために選択されたタイプは、そもそもIEnumerableではなくICollectionであったはずだと思います。

ICollectionICollection<T>の両方がCountプロパティを提供します-さらに-すべてのICollectionはIEnumearableも実装します。

3
Veverke