var list = Students.Where(s=>s.Name == "ABC");
Điều này sẽ chỉ tạo truy vấn và không lặp lại các phần tử cho đến khi truy vấn được sử dụng. Bằng cách gọi ToList() trước tiên sẽ thực hiện truy vấn và do đó chỉ lặp lại các phần tử của bạn một lần.
List<Student> studentList = new List<Student>();
var list = Students.Where(s=>s.Name == "ABC");
foreach(Student s in list)
{
studentList.add(s);
}
ví dụ này cũng sẽ chỉ lặp lại một lần. Bởi vì nó chỉ được sử dụng một lần. Hãy ghi nhớ rằng danh sách sẽ lặp lại tất cả học sinh mọi lúc được gọi là .. Không chỉ những người có tên là ABC. Kể từ khi một truy vấn của nó.
Và đối với các cuộc thảo luận sau, Ive đã thực hiện testexample. Có lẽ nó không phải là thực hiện tốt nhất của IEnumable nhưng nó làm những gì nó phải làm.
Đầu tiên chúng tôi có danh sách của chúng tôi
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);
}
}
Và kể từ khi chúng tôi muốn đếm bao nhiêu lần MoveNext được gọi là chúng ta phải thực hiện aswel tùy chỉnh Enumerator của chúng tôi. Quan sát trong MoveNext chúng ta có một bộ đếm tĩnh trong chương trình của chúng ta.
lớp công khai TestEnumerator: IEnumerator { mục công khai FirstItem = null; mục công khai 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);
}
}
Và sau đó chúng ta có một mục tùy chỉnh mà chỉ kết thúc tốt đẹp giá trị của chúng tôi
public class Item<T>
{
public Item(T item)
{
Value = item;
}
public T Value;
public Item<T> NextItem;
}
Để sử dụng mã thực tế chúng ta tạo ra một "danh sách" với 3 mục.
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.
}
Và kết luận? Làm thế nào để nó đạt hiệu suất? MoveNext được gọi là n + 1 lần trong trường hợp này. Bất kể chúng ta có bao nhiêu món đồ. Và cũng là WhereClause không quan trọng, anh ta vẫn sẽ chạy MoveNext 4 lần. Bởi vì chúng tôi luôn chạy truy vấn của mình trong danh sách ban đầu. Hiệu năng duy nhất mà chúng tôi sẽ thực hiện là khung công tác LINQ thực tế và các cuộc gọi của nó. Các vòng thực tế được thực hiện sẽ giống nhau.
Và trước khi bất kỳ ai hỏi tại sao N + 1 lần và không phải N lần. Bởi vì anh ta trả về sai lầm lần cuối khi anh ấy ra khỏi các yếu tố. Làm cho nó số lượng các yếu tố + kết thúc của danh sách.
Hãy xem 'Where' như một mệnh đề 'if' trong một vòng lặp, không phải là vòng lặp. Trên thực tế, 'Where' sẽ được sử dụng khi' ToList' liệt kê chuỗi. –