2010-05-02 22 views
10

Có cấu trúc dữ liệu nào trong thư viện Bộ sưu tập C# nơi sửa đổi cấu trúc không làm mất hiệu lực vòng lặp không?Có bất kỳ bộ sưu tập C# nào mà sửa đổi không làm mất hiệu lực vòng lặp không?

xem xét như sau:

List<int> myList = new List<int>(); 
myList.Add(1); 
myList.Add(2); 
List<int>.Enumerator myIter = myList.GetEnumerator(); 
myIter.MoveNext(); // myIter.Current == 1 
myList.Add(3); 
myIter.MoveNext(); // throws InvalidOperationException 
+0

Bạn có thể giải thích lý do tại sao bạn cần sửa đổi bộ sưu tập cùng một lúc mà bạn đang đọc từ bộ sưu tập đó không? Có thể có một cách khác để làm những gì bạn muốn. –

Trả lời

-1

Sử dụng một vòng lặp for thay vì một foreach, và sau đó bạn có thể sửa đổi nó. Tôi sẽ không tư vấn cho nó mặc dù ....

+2

Tuy nhiên, điều này không trả lời được câu hỏi. Anh ta hỏi về các trình vòng lặp, không nhất thiết chỉ là các bộ sưu tập được lập chỉ mục. –

+0

Với việc bổ sung phương thức mở rộng ElementAt(), tất cả các bộ sưu tập bây giờ có thể được lập chỉ mục. Tôi nghĩ rằng điều này rất nhiều câu trả lời cho các câu hỏi .... – BFree

0

Không, chúng không tồn tại. Bộ sưu tập tiêu chuẩn ALl C# làm mất hiệu lực tử số khi cấu trúc thay đổi.

1

Cách duy nhất để làm điều này là để tạo ra một bản sao của danh sách trước khi bạn lặp nó:

var myIter = new List<int>(myList).GetEnumerator(); 
8

Theo this MSDN article on IEnumerator hành vi vô hiệu bạn đã tìm thấy được yêu cầu của tất cả các triển khai của IEnumerable.

Điều tra viên vẫn hợp lệ miễn là bộ sưu tập không thay đổi. Nếu thay đổi được thực hiện đối với bộ sưu tập, chẳng hạn như thêm, sửa đổi hoặc xóa yếu tố, thì điều tra viên bị vô hiệu hóa vô hiệu và cuộc gọi tiếp theo tới MoveNext hoặc Đặt lại ném một InvalidOperationException. Nếu bộ sưu tập là được sửa đổi giữa MoveNext và Current, Current trả về phần tử là được đặt thành, ngay cả khi điều tra viên đã bị vô hiệu.

+6

Sau đó, họ đã vi phạm nguyên tắc của riêng họ. Tất cả các bộ sưu tập trong 'System.Collections.Concurrent' cho phép sửa đổi bộ sưu tập giữa các cuộc gọi thành' MoveNext'. –

+0

Đó là do trình vòng lặp duyệt qua ảnh chụp nhanh của bộ sưu tập, do đó ảnh chụp nhanh không bị sửa đổi trong khi lặp lại. – naasking

+1

Đó là những gì tài liệu nói, và tôi hiểu tại sao đó là ý tưởng hay để thêm và loại bỏ các phần tử, nhưng không rõ tại sao sửa đổi một phần tử sẽ làm mất hiệu lực điều tra viên. Tôi có thể hiểu tại sao bạn có thể thực hiện nó theo cách đó, nhưng không phải lý do tại sao bạn nên. – yoyo

11

Có, hãy xem không gian tên System.Collections.Concurrent trong .NET 4.0.

Lưu ý rằng đối với một số bộ sưu tập trong không gian tên này (ví dụ: ConcurrentQueue<T>), điều này chỉ hoạt động bằng cách phơi bày điều tra trên "ảnh chụp nhanh" của bộ sưu tập được đề cập.

Từ the MSDN documentation on ConcurrentQueue<T>:

Việc liệt kê một đại diện cho một khoảnh khắc-in-time chụp của nội dung của hàng đợi. Nó không phản ánh bất kỳ cập nhật nào cho bộ sưu tập sau khi GetEnumerator được gọi. Các điều tra viên là an toàn để sử dụng đồng thời với lần đọc từ và ghi vào hàng đợi .

Đây không phải là trường hợp cho tất cả các bộ sưu tập. ConcurrentDictionary<TKey, TValue>, ví dụ, cung cấp cho bạn một điều tra viên duy trì cập nhật cho bộ sưu tập cơ bản giữa các cuộc gọi đến MoveNext.

Từ the MSDN documentation on ConcurrentDictionary<TKey, TValue>:

Các điều tra viên trở về từ điển là an toàn để sử dụng đồng thời với đọc và viết vào từ điển , tuy nhiên nó không đại diện cho một ảnh chụp khoảnh khắc-in-time của từ điển. Các nội dung tiếp xúc thông qua điều tra viên có thể chứa sửa đổi được thực hiện cho từ điển sau khi GetEnumerator được gọi.

Nếu bạn không có 4.0, thì tôi nghĩ những người khác là đúng và không có bộ sưu tập nào được cung cấp bởi .NET. Bạn luôn có thể xây dựng của riêng bạn, tuy nhiên, bằng cách làm điều tương tự ConcurrentQueue<T> hiện (lặp qua một ảnh chụp nhanh).

+0

Câu trả lời hoàn chỉnh, cảm ơn bạn! Có lẽ bạn biết ConcurrentQueue và ConcurrentStack chụp nhanh như thế nào? Họ có sao chép toàn bộ bộ sưu tập vào một đối tượng mới và liệt kê một bản sao không? Hoặc họ có một số cách thông minh khác để chụp nhanh? – tytyryty

5

Hỗ trợ hành vi này yêu cầu xử lý nội bộ khá phức tạp, vì vậy hầu hết các bộ sưu tập không hỗ trợ điều này (tôi không chắc chắn về không gian tên Concurrent).

Tuy nhiên, bạn có thể mô phỏng rất tốt hành vi này bằng cách sử dụng các bộ sưu tập không thay đổi. Chúng không cho phép bạn sửa đổi bộ sưu tập theo thiết kế, nhưng bạn có thể làm việc với chúng theo cách hơi khác và loại xử lý này cho phép bạn sử dụng đồng thời điều tra mà không xử lý phức tạp (được thực hiện trong bộ sưu tập Concurrent).

Bạn có thể thực hiện một bộ sưu tập như thế một cách dễ dàng, hoặc bạn có thể sử dụng FSharpList<T> từ FSharp.Core.dll (không phải là một phần tiêu chuẩn của .NET 4.0 mặc dù):

open Microsoft.FSharp.Collections; 

// Create immutable list from other collection 
var list = ListModule.OfSeq(anyCollection); 
// now we can use `GetEnumerable` 
var en = list.GetEnumerable(); 

// To modify the collection, you create a new collection that adds 
// element to the front (without actually copying everything) 
var added = new FSharpList<int>(42, list); 

Lợi ích của bộ sưu tập bất biến là bạn có thể làm việc với chúng (bằng cách tạo bản sao) mà không ảnh hưởng đến bản gốc, và vì vậy hành vi bạn muốn là "miễn phí". Để biết thêm thông tin, có một số great series by Eric Lippert.

Các vấn đề liên quan