foreach throws exception, why?
I am getting this exception:
Collection 开发者_如何学编程was modified; enumeration operation may not execute.
when executing this section of code:
List<T> results = new List<T>();
foreach (T item in items)
if (item.displayText.ToLower().Contains(searchText.ToLower()))
results.Add(item);
return results;
I can't see why I get this exception as I'm not changing the contents of the items
list.
With this we have to ask how is the 'items' enumerable produced? Is it a yield
block? Use of yield blocks can suffer from the spectre of delayed execution (i.e. the enumerable not being prepared until the enumerator is accessed) and you can unexpected results from this.
Assuming that the Exception is being thrown from the items enumerator, then the only reason for it to be thrown is if the collection has been modified. Unless it's a custom class implementing its own enumerator, in which case there could simply be a bug in it.
You've discounted the multithreaded environment so I'll ignore that possibility.
Do you still get the error if you 'realise' the enumerable - i.e.
foreach(var item in items.ToArray())
{
//your code.
}
I'll bet you don't, and if not, then something is definitely modifying your items list.
You could check that items
and the result of the .ToArray() call above (you'd have to cache it to a local variable) are still the same at the end of your foreach loop.
Try such code :)
string text = searchText.ToLower();
results = items
.Where(item => item.displayText.ToLower().Contains(text))
.ToList();
The list might be modified by another thread. If that should be the case you have to use proper locking:
lock(items.SyncRoot)
{
foreach (T item in items)
...
}
This locking would also have to be added to all other places where you modify the list.
Since you stated that your code is single-threaded, could you try if the following simple sample program works for you (it does for me)?
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
var items = new List<Item>()
{
new Item() { DisplayText = "A" },
new Item() { DisplayText = "B" },
new Item() { DisplayText = "AB" },
};
var res = filter(items, "A");
}
static List<T> filter<T>(List<T> items, string searchText) where T : Item
{
List<T> results = new List<T>();
foreach (T item in items)
if (item.DisplayText.ToLower().Contains(searchText.ToLower()))
results.Add(item);
return results;
}
}
class Item
{
public string DisplayText { get; set; }
}
Generally I recommend not to ask such questions, but look into exception stack trace. Usually it contains exhaustive answer.
Update: My answer is not correct, you can declare items
of ObservableCollection<T>
type and subscribe on its CollectionChanged
event to determine who exactly changes your collection (-:
精彩评论