Câu hỏi của bạn, theo tôi hiểu, dường như được dựa trên một tiền đề không chính xác. Hãy để tôi xem nếu tôi có thể xây dựng lại lý do:
- Bài viết được liên kết mô tả cách các chuỗi được tạo tự động thể hiện hành vi "lười biếng" và cho thấy cách điều này có thể dẫn đến kết quả phản trực quan.
- Do đó, tôi có thể phát hiện xem một phiên bản cụ thể của IEnumerable sẽ thể hiện hành vi lười biếng này hay không bằng cách kiểm tra xem liệu nó có được tạo tự động hay không.
- Làm thế nào để làm điều đó?
Vấn đề là tiền đề thứ hai là sai. Ngay cả khi bạn có thể phát hiện xem một IEnumerable cụ thể có phải là kết quả của phép chuyển đổi khối lặp hay không (và vâng, có nhiều cách để làm điều đó) sẽ không có ích vì giả định là sai. Hãy minh họa tại sao.
class M { public int P { get; set; } }
class C
{
public static IEnumerable<M> S1()
{
for (int i = 0; i < 3; ++i)
yield return new M { P = i };
}
private static M[] ems = new M[]
{ new M { P = 0 }, new M { P = 1 }, new M { P = 2 } };
public static IEnumerable<M> S2()
{
for (int i = 0; i < 3; ++i)
yield return ems[i];
}
public static IEnumerable<M> S3()
{
return new M[]
{ new M { P = 0 }, new M { P = 1 }, new M { P = 2 } };
}
private class X : IEnumerable<M>
{
public IEnumerator<X> GetEnumerator()
{
return new XEnum();
}
// Omitted: non generic version
private class XEnum : IEnumerator<X>
{
int i = 0;
M current;
public bool MoveNext()
{
current = new M() { P = i; }
i += 1;
return true;
}
public M Current { get { return current; } }
// Omitted: other stuff.
}
}
public static IEnumerable<M> S4()
{
return new X();
}
public static void Add100(IEnumerable<M> items)
{
foreach(M item in items) item.P += 100;
}
}
Được rồi, chúng tôi có bốn phương pháp. S1 và S2 là các chuỗi được tạo tự động; S3 và S4 là các chuỗi được tạo thủ công. Bây giờ giả sử chúng ta có:
var items = C.Sn(); // S1, S2, S3, S4
S.Add100(items);
Console.WriteLine(items.First().P);
Kết quả cho S1 và S4 sẽ là 0; mỗi khi bạn liệt kê chuỗi, bạn sẽ có một tham chiếu mới đến một M được tạo. Kết quả cho S2 và S3 sẽ là 100; mỗi khi bạn liệt kê trình tự, bạn sẽ có cùng tham chiếu đến M bạn đã nhận được lần cuối cùng. Liệu mã trình tự có được tạo tự động hay không trực giao với câu hỏi liệu các đối tượng được liệt kê có nhận dạng tham chiếu hay không. Hai thuộc tính đó - tạo tự động và nhận dạng tham chiếu - thực sự không liên quan gì đến nhau. Bài viết bạn liên kết để xúi giục họ phần nào.
Trừ khi một nhà cung cấp trình tự được ghi nhận là luôn luôn khuyến khích các đối tượng có danh tính tham chiếu , sẽ không khôn ngoan khi cho rằng nó làm như vậy.
ICollection<T>
sẽ là lựa chọn tốt hơn vì không phải tất cả các bộ sưu tập đều như vậyList<T>
. Ví dụ, mảngPoint[]
thực hiệnIList<T>
nhưng khôngList<T>
.