Giới thiệu
Để lấy enumerator (bộ đếm) duyệt qua các phần tử của List<T>, sử dụng phương thức GetEnumerator(). Enumerator cho phép duyệt tuần tự mà không cần biết cấu trúc nội bộ.
Cú pháp
public List<T>.Enumerator GetEnumerator ();
Trả về struct List<T>.Enumerator triển khai IEnumerator<T>.
Ví dụ 1: Duyệt List với GetEnumerator()
using System;
using System.Collections.Generic;
public class Demo {
public static void Main(String[] args) {
List list1 = new List();
list1.Add("One");
list1.Add("Two");
list1.Add("Three");
list1.Add("Four");
list1.Add("Five");
Console.WriteLine("Các phần tử trong List1...");
foreach (string item in list1) {
Console.WriteLine(item);
}
List list2 = new List();
list2.Add("India");
list2.Add("US");
list2.Add("UK");
list2.Add("Canada");
list2.Add("Poland");
list2.Add("Netherlands");
Console.WriteLine("\nCác phần tử trong List2...");
List.Enumerator enumerator = list2.GetEnumerator();
while (enumerator.MoveNext()) {
string item = enumerator.Current;
Console.WriteLine(item);
}
Console.WriteLine("\nList2 bằng List1? = " + list2.Equals(list1));
}
}
Đầu ra ví dụ 1
Các phần tử trong List1... One Two Three Four Five Các phần tử trong List2... India US UK Canada Poland Netherlands List2 bằng List1? = False
Ví dụ 2: Duyệt List lớn hơn
using System;
using System.Collections.Generic;
public class Demo {
public static void Main(String[] args) {
List list = new List();
list.Add("One");
list.Add("Two");
list.Add("Three");
list.Add("Four");
list.Add("Five");
list.Add("Six");
list.Add("Seven");
list.Add("Eight");
list.Add("Nine");
list.Add("Ten");
Console.WriteLine("Enumerator duyệt qua các phần tử list...");
List.Enumerator enumerator = list.GetEnumerator();
while (enumerator.MoveNext()) {
string item = enumerator.Current;
Console.WriteLine(item);
}
}
}
Đầu ra ví dụ 2
Enumerator duyệt qua các phần tử list... One Two Three Four Five Six Seven Eight Nine Ten
Cấu trúc Enumerator
public struct Enumerator : IEnumerator<T>, IDisposable, IEnumerator {
public T Current { get; }
public bool MoveNext();
public void Reset(); // Không hỗ trợ, ném NotSupportedException
void IDisposable.Dispose(); // Không làm gì cho List
}
Lưu ý quan trọng
foreachtự động gọiGetEnumerator(),MoveNext(),Current, vàDispose(). Khuyến nghị dùngforeachthay vì manual enumerator.- Enumerator là struct (value type), tránh allocation heap.
- Không sửa đổi list (Add/Remove/Clear) khi đang enumerating → ném
InvalidOperationException. Reset()không được hỗ trợ trong List.Enumerator.Currentchỉ hợp lệ sau khiMoveNext()trả về true.
So sánh foreach vs Manual Enumerator
| Đặc điểm | foreach | Manual Enumerator |
|---|---|---|
| Cú pháp | Ngắn gọn, dễ đọc | Verbose |
| An toàn | Tự động Dispose | Cần tự Dispose (dùng using) |
| Linh hoạt | Khó kiểm soát luồng | Dễ dàng pause/resume, skip, nested loop |
| Hiệu năng | Tương đương | Tương đương |
Khi nào dùng Manual Enumerator?
- Cần duyệt song song hai list (zip-like).
- Cần lookahead (xem phần tử tiếp theo không consume).
- State machine phức tạp, yield return custom.
- Interop với API yêu cầu IEnumerator.