2010-08-17 24 views
21
foreach(BruteforceEntry be in Entries.Values) 
{ 
    if (be.AddedTimeRemove <= now) 
     Entries.Remove(be.IPAddress); 
    else if (be.Unbantime <= now && be.Unbantime.Day == DateTime.Now.Day) 
     Entries.Remove(be.IPAddress); 
} 

Một ngoại lệ được ném:Sửa đổi một từ điển mà tôi đang lặp lại qua

Bộ sưu tập đã được sửa đổi; hoạt động điều tra có thể không thực hiện được.

Vì lý do nào đó, nó không còn nữa.

Tôi biết bạn không thể xóa nội dung nào đó, trong khi lặp lại theo cách này. Câu hỏi của tôi là: Làm thế nào để giải quyết nó?

Trả lời

34

Bạn không thể sửa đổi bộ sưu tập bạn đang lặp lại. Trong trường hợp này, một giải pháp tốt hơn sẽ là để tạo ra một danh sách các mục để loại bỏ bằng cách duyệt qua từ điển, và sau đó lặp qua rằng danh sách, loại bỏ các mục từ điển:

List<string> removals = new List<string>();      
DateTime now = DateTime.Now; 
foreach(BruteforceEntry be in Entries.Values) 
{ 
    if (be.AddedTimeRemove <= now || 
     (be.Unbantime <= now && be.Unbantime.Day == DateTime.Now.Day)) 
    { 
     removals.Add(be.IPAddress); 
    } 
} 
foreach (string address in removals) 
{ 
    Entries.Remove(address); 
} 

Lưu ý rằng nếu bạn đang sử dụng .NET 3.5, bạn có thể sử dụng một truy vấn LINQ để diễn tả phần đầu tiên:

List<string> removals = (from be in Entries.Values 
         where be.AddedTimeRemove <= now || 
           (be.Unbantime <= now && 
           be.Unbantime.Day == DateTime.Now.Day) 
         select be.IPAddress).ToList(); 
+1

Cảm ơn rất nhiều. Tôi có 1 câu hỏi, bạn có thích điều này nhiều hơn simly iterating thông qua một bản sao, bằng cách sử dụng. ToList() vì đó là một chỉnh sửa nhỏ hơn. – Basser

+1

@Basser: Vâng, có một điều có khả năng có dấu chân bộ nhớ nhỏ hơn. Nó cũng chỉ lặp lại toàn bộ bộ sưu tập một lần - giải pháp hiện tại của bạn lặp lại một lần để xây dựng danh sách và sau đó nó lặp lại trong danh sách đó. Đừng làm cho tôi sai - nó sẽ hoạt động ... Tôi chỉ thích cách tiếp cận này. –

+0

Tôi vừa được thông báo rằng một người dùng SO hàng đầu đã trả lời câu hỏi của tôi, đó là lý do tại sao tôi nghĩ tôi sẽ hỏi bạn! Tôi đoán tôi sẽ sử dụng phương pháp này, như bạn là chính xác! Cảm ơn một lần nữa. Tôi chưa quá tốt với các bộ sưu tập, vẫn đang học hỏi. – Basser

1

Bạn không thể sửa đổi bộ sưu tập khi lặp lại bộ sưu tập với foreach. Thay vào đó, lặp lại nó với một vòng lặp for.

+2

Nếu đi của bạn được xóa mục khỏi bộ sưu tập, hãy chắc chắn để lặp qua nó trong đảo ngược (từ chiều dài-1 đến 0) và không 0 đến chiều dài-1 –

+1

Bạn tốt hơn lặp lại ngược nếu bạn đang xóa các mục và cập nhật biến gia tăng của bạn cho phù hợp nếu thêm. Điều này dễ bị sai lầm. – Marc

+5

Lặp lại từ * từ điển * với vòng lặp for kinda khó hiểu ... –

2

bạn có thể thay đổi foreach(BruteforceEntry be in Entries.Values)-foreach(BruteforceEntry be in new List<BruteforceEntry>(Entries.Values))

bằng cách đó bạn không sửa đổi bộ sưu tập của bạn, nhưng ra có một bản sao của nó.

+0

Cảm ơn bạn, điều này sẽ làm việc nếu một người nào khác không trả lời. – Basser

+0

Điều này sẽ không hoạt động vì bạn vẫn đang nhận được một trình lặp từ Danh sách <>. Đó là trình lặp, không phải bộ sưu tập, gây ra sự cố. –

+0

Nó chắc chắn hoạt động, bạn không phải loại bỏ khỏi List <> iterator, bạn đang loại bỏ khỏi từ điển <> iterator. Danh sách <> liệt kê toán tử Dictionary <> đầy đủ trước khi loại bỏ đầu tiên khỏi từ điển. –

0

sôi xuống vấn đề của bạn ...

foreach(... ... in Entries.Values) 
{ 
     Entries.Remove(...); 

} 

Như những người khác đã nói bạn đang sửa đổi iterator trong khi iterating.

Bạn có thể, như @ David cho biết, sử dụng vòng lặp for thay thế, nhưng hãy đảm bảo bắt đầu ở cuối (lặp lại ngược lại).

8

Chỉ cần đặt: bạn không thể xóa mục nhập khỏi bộ sưu tập trong khi bạn đang lặp lại nó.

Một workaround có thể là tạo ra một bản sao cạn của bộ sưu tập (ví dụ sử dụng ToList) và duyệt qua rằng:

foreach(BruteforceEntry be in Entries.Values.ToList()) 
{ 
    // modify the original collection 
} 
+0

Cảm ơn bạn, điều này đã giải quyết được câu hỏi của tôi. – Basser

+0

Điều này sẽ không hoạt động vì bạn vẫn đang nhận được một trình lặp từ Danh sách <>. Đó là trình lặp, không phải bộ sưu tập, gây ra sự cố. –

+0

Giải pháp của tôi chỉ là một ví dụ về giải pháp thay thế. Về hiệu suất, và rõ ràng tôi đề nghị bạn áp dụng giải pháp của Jon;) – digEmAll

2

Dường như câu hỏi của bạn là về việc tại sao một ngoại lệ là không bị ném nơi nó từng là. Vì các câu trả lời khác nói chung, bạn thường không thể thay đổi một bộ sưu tập mà bạn đang lặp lại, nhưng bạn đang lặp qua bộ sưu tập Giá trị, mà tôi tin là bản sao của các giá trị trong từ điển, thay vì tham chiếu đến bộ sưu tập từ điển chính chinh no. Vì vậy, nó không còn có vấn đề lặp lại và sửa đổi cùng một điều.

1

này (theo ý kiến ​​của tôi) là cách dễ nhất:

Dictionary<String, String> A = new Dictionary<string, string>(); //Example Dictionary 
A.Add("A", "A"); //Example Values 
A.Add("B", "B"); 
A.Add("C", "C"); 

for (int i = A.Count - 1; i >= 0; i--) //Loop backwards so you can remove elements. 
{ 
    KeyValuePair<String, String> KeyValue = A.ElementAt(i); //Get current Element. 
    if (KeyValue.Value == "B") A.Remove(KeyValue.Key); 
} 

Trong trường hợp của bạn:

for (int i = Entries.Count - 1; i >= 0; i--) 
{ 
    KeyValuePair<String, BruteforceEntry> KeyValue = Entries.ElementAt(i); 
    if (KeyValue.Value.AddedTimeRemove <= now) 
     Entries.Remove(KeyValue.Key); 
    else if (KeyValue.Value.Unbantime <= now && KeyValue.Value.Unbantime.Day == DateTime.Now.Day) 
     Entries.Remove(KeyValue.Key); 
} 
+1

-1 Trong khi điều này có thể hoạt động đối với một số triển khai .NET, lớp 'Từ điển ' không ** đảm bảo ** thứ tự của các phần tử của nó (khi được lặp lại như là một 'IEnumerable > ') không thay đổi khi từ điển được sửa đổi. – Ergwun

+1

Từ http://msdn.microsoft.com/en-us/library/xfhwa508.aspx: "Với mục đích liệt kê, mỗi mục trong từ điển được coi là cấu trúc KeyValuePair đại diện cho một giá trị và khóa của nó. Thứ tự các mục được trả về là không xác định." – Ergwun

+1

Ahh, tôi không biết điều này, cảm ơn vì đã làm rõ! – Blam

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