var list = Students.Where(s=>s.Name == "ABC");
これはクエリを作成するだけで、クエリが使用されるまで要素をループしません。ToList() を呼び出すと、最初にクエリが実行され、要素が 1 回だけループされます。
List<Student> studentList = new List<Student>();
var list = Students.Where(s=>s.Name == "ABC");
foreach(Student s in list)
{
studentList.add(s);
}
この例も 1 回だけ繰り返します。一度しか使っていないからです。リストは、呼び出されるたびにすべての生徒を反復することに注意してください。名前が ABC の生徒だけではありません。そのクエリ以来。
そして、後の議論のために、私はテスト例を作りました。おそらくこれは IEnumable の最適な実装ではありませんが、本来の機能を果たします。
まず、リストがあります
public class TestList<T> : IEnumerable<T>
{
private TestEnumerator<T> _Enumerator;
public TestList()
{
_Enumerator = new TestEnumerator<T>();
}
public IEnumerator<T> GetEnumerator()
{
return _Enumerator;
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new NotImplementedException();
}
internal void Add(T p)
{
_Enumerator.Add(p);
}
}
そして、MoveNext が呼び出された回数をカウントしたいので、カスタム列挙子 aswel を実装する必要があります。MoveNext で、プログラムに静的なカウンターがあることを確認します。
public class TestEnumerator : IEnumerator { public Item FirstItem = null; public Item CurrentItem = null;
public TestEnumerator()
{
}
public T Current
{
get { return CurrentItem.Value; }
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current
{
get { throw new NotImplementedException(); }
}
public bool MoveNext()
{
Program.Counter++;
if (CurrentItem == null)
{
CurrentItem = FirstItem;
return true;
}
if (CurrentItem != null && CurrentItem.NextItem != null)
{
CurrentItem = CurrentItem.NextItem;
return true;
}
return false;
}
public void Reset()
{
CurrentItem = null;
}
internal void Add(T p)
{
if (FirstItem == null)
{
FirstItem = new Item<T>(p);
return;
}
Item<T> lastItem = FirstItem;
while (lastItem.NextItem != null)
{
lastItem = lastItem.NextItem;
}
lastItem.NextItem = new Item<T>(p);
}
}
そして、値をラップするカスタムアイテムがあります
public class Item<T>
{
public Item(T item)
{
Value = item;
}
public T Value;
public Item<T> NextItem;
}
実際のコードを使用するには、3 つのエントリを持つ「リスト」を作成します。
public static int Counter = 0;
static void Main(string[] args)
{
TestList<int> list = new TestList<int>();
list.Add(1);
list.Add(2);
list.Add(3);
var v = list.Where(c => c == 2).ToList(); //will use movenext 4 times
var v = list.Where(c => true).ToList(); //will also use movenext 4 times
List<int> tmpList = new List<int>(); //And the loop in OP question
foreach(var i in list)
{
tmpList.Add(i);
} //Also 4 times.
}
そして結論?パフォーマンスにどのように影響しますか?この場合、MoveNext は n+1 回呼び出されます。アイテムの数に関係なく。また、WhereClause は問題ではなく、MoveNext を 4 回実行します。常に最初のリストでクエリを実行するためです。唯一のパフォーマンス ヒットは、実際の LINQ フレームワークとその呼び出しです。作成される実際のループは同じになります。
そして、なぜ N 回ではなく N+1 回なのかを誰かが尋ねる前に。これは、要素がなくなったときに最後に false を返すためです。要素数+リストの終わりにします。