私は最近、.NETのLINQ実装で作成されたオブジェクトが、特定の列挙型に対して非効率的であることを知りました。C#:IEnumerable <T> .Select()は効率的でない場合がありますか?
は、このコードを見てみましょう:
public class DummyCollection : ICollection<int>
{
public IEnumerator<int> GetEnumerator()
{
throw new Exception();
}
public int Count
{
get
{
return 10;
}
}
//some more interface methods
}
は基本的に、DummyCollectionのインスタンスは、10の大きさを持っているが、それが実際に列挙されている場合は例外をスローします。
今ここで:
var d = new DummyCollection();
Console.WriteLine(d.Count());
10がエラーなしで印刷が、コードのこの部分である:
var l = d.Select(a=> a);
Console.WriteLine(l.Count());
は、Lのサイズが10となると言うことが自明であるにもかかわらず、例外をスロー(Selectは1対1マッピングを提供するので)。これは、基本的には、Ienumerableの長さをチェックするとき、入力がSelect-wrapped Collectionであり、計算時間をO(1)から驚異的なO(n)に延長することができます選択機能は特に煩雑である)。
LINQのジェネリックスを求めるときに効率を犠牲にすることがわかっていますが、これは修正するのが簡単な問題のようです。私はオンラインでチェックし、誰かがこれに対処できなかった。この欠点を回避する方法はありますか?誰もこれを調べているのですか?誰でもこれを修正していますか?これはそれほど大きな問題ではない、ちょっとしたケースですか?どんな洞察にも感謝します。
とにかく、 'GetEnumerator'で例外を投げて、どんな場合でも' Count() 'を呼び出すことができるのは本当ですか? –
@MatíasFidemraizer例外スローは、可能な限り列挙を避けるための単なるプレースホルダです。これは、非常に長いメソッド呼び出し、または非常に大きなコレクション、または列挙時に変更されるコレクション(非同期環境では危険なオブジェクトのロックなど)に置き換えることができます。 – bentheiii
'OrderBy'にも同じ問題があります。 'OrderBy'はカウントを変更しませんが、' Count() 'を呼び出すとまだ完全なソートが実行されます。あなたはいくつかの反射shenaningansを使用してソートせずに正しいカウントを得ることができます。 http://stackoverflow.com/questions/17493076/count-an-iorderedenumerered-umer-without-consuming-it – HugoRune