最近、1つのプログラムのコードを解析しているときに、次のようなメソッドに気付きました。
public void Foo<T>( IEnumerable <T> items)
{
if (items == null || items.Count() == 0)
{
//
}
}
このメソッドは一般的な列挙を受け入れ、空かどうかを確認します。 ここに潜在的な問題がありますか? 問題はこの行にあります:
items.Count()== 0
そして、ここでの問題は何ですか? 問題は、この行が非常に非効率になる可能性があることです。
メソッドを呼び出して、
ICollection <T>を実装していない列挙(Entity Frameworkへのクエリの
IQueryable結果やLINQ to SQLなど)を渡すと、
Count()メソッドはこのチェックを実行するためにコレクション全体を反復処理します。
列挙が
ICollection <T>を実装する場合、すべてが
正常です 。
Count()メソッドは、このような場合に最適化されており、
Countプロパティをチェックし
ます 。
人間の言葉で言えば、私たちのライン
は 「
リストの量はゼロに等しいですか?」という質問に答え
ます。 「。 しかし、これは私たちの興味を引くものではありません。 実際、「
列挙に少なくとも1つの要素がありますか? 」という質問に答える必要があり
ます。 「。
この方法でタスクにアプローチすると、ソリューションが明らかになります
。System.Linq名前空間の
Any拡張機能を使用します。
public void Foo<T>( IEnumerable <T> items)
{
if (items == null || !items.Any())
{
//
}
}
このメソッドの
利点は 、
IEnumerableインターフェイスの
MoveNextを 1回だけ呼び出す必要があることです! 無限に大きな列挙がある場合がありますが、
Anyはすぐに結果を返します。
そのようなチェックは常に使用されるため、単純な拡張メソッドの実装を検討するのがさらに良いでしょう。
public static bool IsNullOrEmpty<T>( this IEnumerable <T> items)
{
return items == null || !items.Any();
}
さて、このメソッドを使用すると、ソースコードはさらに簡単になります。
public void Foo<T>( IEnumerable <T> items)
{
if (items.IsNullOrEmpty())
{
//
}
}
ツールキットでこの拡張メソッドを使用すると、無効な列挙を非効率的にチェックすることはありません。