誰でもCount
のIEnumerable
拡張メソッド(非汎用インターフェース)で私を助けることができます。
LINQではサポートされていませんが、手動で記述する方法は知っていますか?
最も単純な形式は次のとおりです。
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
/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;
}
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;
}
}
IEnumerableの種類によって、カウントを決定するための最適な方法が異なります。残念ながら、どのメソッドが特定のIEnumerableに最適であるかを知るための汎用的な手段はなく、IEmumerableが次のテクニックのどれが最適であるかを示す標準的な手段すらありません。
上記のそれぞれは、異なる場合に最適です。
要素のシーケンスを表すために選択されたタイプは、そもそもIEnumerableではなくICollectionであったはずだと思います。
ICollection
とICollection<T>
の両方がCountプロパティを提供します-さらに-すべてのICollectionはIEnumearableも実装します。