Collection was modified; enumeration operation may not execute - c#

I have multiple TabItems in my TabControl; tabItem1, tabItem2, tabItem3...these are
CloseableTabItem.
If I add a node in tabItem1 and press a button to make a subGraph model for this node, the
same node should appear in tabItem2 with a button; so that
tabItem2-Header = nodeName and nodeName = tabItem1-Header.
if i press the button from the node in tabitem2, tabitem1 should be focused. if i close
tabItem1 and press the same Button tabItem1 should be loaded again(this happen in
SubGraphButton_Click).
Do you see a problem with this code?
private void ChildNode_Click(object sender, RoutedEventArgs args)
{
System.Windows.Controls.Button button = (System.Windows.Controls.Button)sender;
Node node = Part.FindAncestor<Node>(button);
MyNodeData nodeData = node.Data as MyNodeData;
foreach (TabItem item in tabControl.Items)
{
if (nodeData.Text == item.Header.ToString())
{
item.Focus();
}
else if (nodeData.Text != item.Header.ToString())
{
SubGraphButton_Click(sender, args);
}
}
}
private void SubGraphButton_Click(object sender, RoutedEventArgs args)
{
string activeDirectory = #"X:\SubGraph\";
string[] files = Directory.GetFiles(activeDirectory);
foreach (string fileName in files)
{
FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
System.Windows.Controls.Button button = (System.Windows.Controls.Button)sender;
Node node = Part.FindAncestor<Node>(button);
MyNodeData nodeData = node.Data as MyNodeData;
if (node != null)
{
if (nodeData.Text + ".epk" == fileName.Substring(12, fileName.Length - 12) && !tabControl.Items.Contains(tabItem1))
{
tabControl.Items.Add(tabItem1);
tabItem1.Focus();
var model = new MyGraphLinksModel();
model.Modifiable = true;
model.HasUndoManager = true;
activateDiagram(myDiagram1);
activeDiagram.Model = model;
model.Name = fileName.Substring(12, fileName.Length - 12);
model.Name = model.Name.Substring(0, model.Name.Length - 4);
tabItem1.Header = model.Name;
activeDiagram.PartManager.UpdatesRouteDataPoints = false;
StreamReader reader = new StreamReader(file);
string contents = reader.ReadToEnd();
XElement root = XElement.Parse(contents);
activeDiagram.LayoutCompleted += LoadLinkRoutes;
model.Load<MyNodeData, MyLinkData>(root, "MyNodeData", "MyLinkData");
}
}
}

When you modify a collection when it is in the middle of being modified it is rather likely to cause errors. The types of errors, and their likeliness, tend to vary based on what the underlying collection actually is. Modifying a List when iterating it is very likely to give you lots of off by one errors (or off by more than one if you modify it a lot) and potentially out of bounds errors. Modifying a LinkedList could result in null pointer exceptions, infinite loops, accessing non-existent items, etc. but is quite a bit less likely.
Because the chances of problems, in the general case, are rather high, the impact of those problems is also rather high, and the difficulty in diagnosing what actually went wrong (and where) C# chooses to just throw an exception whenever you try to iterate a collection that was modified during the iteration. This way you don't end up with weird, unexpected problems that don't manifest themselves until some time much further down the road then where their root cause is.
There are several different strategies that can be used to avoid this issue:
Iterate over a different collection than the one you really want to modify. In some cases this can simply be done by adding a ToList call on a sequence so that it is moved to a new collection; when doing this the collection being iterated is separate from the one being modified and so there is no error.
You can avoid modifying the actual collection inside of the foreach loop. Common examples of this are creating a List or other collection of "changes to make" whether it's itemsToAdd, itemsToRemove etc. Then you can add/remove/whatever for all of those items after the loop. (This is effective if you are only modifying a small percentage of the size of the collection.)
Certain types of collections can be "iterated" without actually using a traditional iterator (meaning a foreach loop). As an example, you can iterate through a List using a regular for loop instead, and simply modify (increment/decrement) the loop variable whenever you add or remove items. This, when done correctly, tends to be an efficient option, but it's quite easy to make a mistake and get something wrong so while the other options are (marginally) less efficient, they are very good options for non-performance intensive code due to their simplicity.

you can't modify collection you're iterating on.
you can replace the "foreach" loop with simple "for" loop but notice the index you're running on when adding/removing items from the collection.
like this:
for (int i = 0; i < tabControl.Items.Count; i++)
{
TabItem item = tabControl.Items[i];
... // your logic here
}
another option which might be convenient, is instead of adding the items into the tab control.Items collection is getting it as return value, save them in a list and after you've done iterating all the items, insert all the tabs you've created into the items collection so you're not modifying the collection while you're running on it.

You are not permitted to modify a collection (tabControl.Items in this case) while you are enumerating it (which you are doing in your foreach loop) as it will make the enumerator invalid.
The specific line of code which is causing the error is likely to be
// In SubGraphButton_Click
// This line of code is called inside an enumeration of tabControl.Items
// This is not permitted!
tabControl.Items.Add(tabItem1);
Conceptually, your code looks like this:
private void ChildNode_Click(object sender, RoutedEventArgs args)
{
System.Windows.Controls.Button button = (System.Windows.Controls.Button)sender;
Node node = Part.FindAncestor<Node>(button);
MyNodeData nodeData = node.Data as MyNodeData;
foreach (TabItem item in tabControl.Items)
{
if (nodeData.Text == item.Header.ToString())
{
item.Focus();
}
else if (nodeData.Text != item.Header.ToString())
{
// This line will throw an exception
DoSomethingThatModifiesTabControlItemsCollection()
}
}
}

Inside the foreach loop you call SubGraphButton_Click which in turn adds a new node tabControl.Items.Add(tabItem1);
This is not allowed. You can use a for loop instead.

Yes, this line
tabControl.Items.Add(tabItem1);
changes the collection on which you enumerate in the NodeClick
and this is no-no in the enumeration world
Try to loop with a standard for, but in reverse order......
for( int x = tabControl.Items.Count - 1; x>= 0; x--)
{
TabItem item = tabControl.Items[x];
if (nodeData.Text == item.Header.ToString())
{
item.Focus();
}
else if (nodeData.Text != item.Header.ToString())
{
SubGraphButton_Click(sender, args);
}
}
Looping in reverse order avoid to examine the new items added inside the SubGraphButton.
I don't know if this is a desidered effect or not.

When you ForEach over the TabItems in tabControl, you can't do anything inside the ForEach that will cause the tabControl's items collection to change.
This is a limitation of the framework. It is because you are currently iterating over the TabItems.
So inside of your ChildNode_Click function,
Inside of your ForEach
foreach (TabItem item in tabControl.Items)
you make a call to
SubGraphButton_Click(sender, args);
Inside of that function, you make a call to
tabControl.Items.Add(tabItem1);
You can't manipulate the Items collection while inside the ForEach.

Related

C# Collection ConcurrentBag reverse itens during concurrency update

I using a ConcurrentBag as Collection that is thread safe, to avoid conflicts when i am updating my collection in differents threads.
But i notice that sometimes the itens get inverse, my firts item goes to the last position of my collection.
I just wanna know if this may be happening due to change the collection in concurrency. If it's not possible what could may be messing up my collection?
Edit: I'm adding some sample code.
When i need to add a item i make this:
var positionToInsert = (int)incremental.MDEntryPositionNo - 1;
concurrentList.ToList().Insert(positionToInsert, myListInfoToInsert);
In some cases i need to update a position so i do like this
var foundPosition = concurrentList.ToList()
.FirstOrDefault(orderBook => orderBook.BookPosition == incremental.MDEntryPositionNo);
var index = concurrentList.ToList().IndexOf(foundPosition);
if (index != -1)
{
concurrentList.ToList()[index] = infoToUpdate;
}
Thaks!
Edited: Just use sorting, don't use insertion it's a slow operation.
var orderedBooks = concurrentList.OrderBy(x=>x.BookPosition).ToList();
ConcurrentBag is implemented as a linked list, and the ToList code is shown below.
For each input thread, created own ThreadLocalList or reused free.
The head of a linked list is always the same, and I don't understand how the order can change in this situation. However you can't guarantee that the last item added won't be in the first bucket.
Please add your sample code.
private List<T> ToList()
{
List<T> objList = new List<T>();
for (ConcurrentBag<T>.ThreadLocalList threadLocalList = this.m_headList; threadLocalList != null; threadLocalList = threadLocalList.m_nextList)
{
for (ConcurrentBag<T>.Node node = threadLocalList.m_head; node != null; node = node.m_next)
objList.Add(node.m_value);
}
return objList;
}

adding or removing from an observable collection within ForEach

I don't think I can modify the observable collection 'varieties' in the foreach loop below - whenever the conditions in the 'if' are met the 'Remove' happens then the foreach exists when it still has the bulk of the collection to go through.
I changed it so that if the condition was met rather than remove from varieties it adds the variety to a new list, but again as soon as the condition is met for the first time the foreach exist.
Am I missing something?
foreach (Variety variety in varieties)
{
if (variety.Type != main.Type && variety.Type != null)
{
varieties.Remove(variety);
}
}
changed code:
foreach (Variety variety in varieties)
{
if (variety.Type == main.Type || variety.Type == null)
{
FilteredVarieties.Add(variety);
}
}
You cannot modify the source collection inside the foreach. If you really want to modify ,try having a copy to loop in foreach and modify it inside.
var sourcecopy=varieties;
foreach (Variety variety in sourcecopy)
{
if (variety.Type != main.Type && variety.Type != null)
{
varieties.Remove(variety);
}
}
You can't remove an item from your collection in a foreach loop. What is going on when you say foreach is it is really creating a for loop that goes from 0 to the original count of the collection. So once you remove something and the count of the collection changes, the range for the loop does not get updated.
If you switch to a normal for loop, you should be good though.
As others (and the compiler) have probably said, you can't change a collection that you are enumerating through in that way. However, if you .ToList() your collection in the foreach definition, you are actually enumerating a copy of your list, so are free to remove or add to your original list.
foreach (Variety variety in varieties.ToList())
{
if (variety.Type != main.Type && variety.Type != null)
{
varieties.Remove(variety);
}
}

Prevent infinite loop between objects referencing each other?

Okay, so I wasn't completely sure what headline would fit my problem, but here goes the description:
I have objects than can reference other objects, to create dropdown lists where the content/values is dependant on what values is chosen in "parent" dropdowns.
My dropdown objects contain an id, and a parentId (and other stuff, not relevant here).
I want to prevent the users from making infinite loops, like this:
List 1 (Dependant on list 3)
List 2 (Dependant on list 1)
List 3 (Dependant on list 2)
I've tried writing a recursive method to prevent it, but I cannot figure out the logic.
Could anyone tell me how you would ensure that an object isn't referencing it self "down the line" ? Or provide an example perhaps.
Any help is much appreciated.
The simplest way I can think of is to create a flattened list. Recursively iterate the objects and store each reference in a list. As you find new objects check each one in the list.
You'll either encounter an object referencing itself or run out of objects to search.
This method being suitable will depend on your requirements, speed / memory/ number of items in the list.
Since all object contain an id the list could store/check that instead if you need to check value equality instead of reference equality
If you have written a recursive function to manage those lists, one solution could be to create a list of elements and pass it as parameter into the recursive function and en each iteration add the current item to the list. To stop the recursive function, only check if the current item has been added previously to the list.
If you iterate through the actual elements of each list by relying on specific counters for each list you shouldn't find any problem. The most likely way to provoke an infinite loop is changing the value of a counter from an external source. Example:
for(int i = 0; i < max_i; i++)
{
if(val1[i] != null)
{
for(int j = 0; j < max_j; j++)
{
if(val2[j] != null)
{
//Delete or anything
//YOU CANNOT AFFECT NEITHER i NOR j DIRECTLY.
}
}
}
If you want to account for varying values of j in the internal part, you should rely on a different variable. Example:
if(val2[j] != null)
{
int j2 = j;
//Do whatever with j2, never with j
}
By doing this (associating different counters to different loops), no endless loop will occur. An endless loop occurs when: i = 1, 2, 3, 4 and suddenly i is changed to 2 by an "external source"; thus solution: NEVER change i other than through the for loop.
Thanks everyone for your input on this. I went with James suggestion using a list and ended up with the following code (which may or may not make sense for anyone else but me)
public static bool BadParent(int fieldId, int childId, List<int> list)
{
if (list == null)
list = new List<int>();
bool returnValue = true;
var field = EkstraFelterBLL.getEkstraFeltUdfraEkstraFeltId(fieldId);
if (field != null)
{
if (field.ParentEkstraFeltId == childId)
returnValue = false; //loop reference, fail
else if (list.Contains(field.EkstraFeltId))
returnValue = false; //already been in the cycle, fail
else
{
list.Add(field.EkstraFeltId);
returnValue = BadParent(field.ParentEkstraFeltId, childId, list);
}
}
return returnValue;
}

Intelligent way of removing items from a List<T> while enumerating in C#

I have the classic case of trying to remove an item from a collection while enumerating it in a loop:
List<int> myIntCollection = new List<int>();
myIntCollection.Add(42);
myIntCollection.Add(12);
myIntCollection.Add(96);
myIntCollection.Add(25);
foreach (int i in myIntCollection)
{
if (i == 42)
myIntCollection.Remove(96); // The error is here.
if (i == 25)
myIntCollection.Remove(42); // The error is here.
}
At the beginning of the iteration after a change takes place, an InvalidOperationException is thrown, because enumerators don’t like when the underlying collection changes.
I need to make changes to the collection while iterating. There are many patterns that can be used to avoid this, but none of them seems to have a good solution:
Do not delete inside this loop, instead keep a separate “Delete List”, that you process after the main loop.
This is normally a good solution, but in my case, I need the item to be gone instantly as “waiting” till after
the main loop to really delete the item changes the logic flow of my code.
Instead of deleting the item, simply set a flag on the item and mark it as inactive. Then add the functionality of pattern 1 to clean up the list.
This would work for all of my needs, but it means that a lot of code will have to change in order to check the inactive flag every time an item is accessed. This is far too much administration for my liking.
Somehow incorporate the ideas of pattern 2 in a class that derives from List<T>. This Superlist will handle the inactive flag, the deletion of objects after the fact and also will not expose items marked as inactive to enumeration consumers. Basically, it just encapsulates all the ideas of pattern 2 (and subsequently pattern 1).
Does a class like this exist? Does anyone have code for this? Or is there a better way?
I’ve been told that accessing myIntCollection.ToArray() instead of myIntCollection will solve the problem and allow me to delete inside the loop.
This seems like a bad design pattern to me, or maybe it’s fine?
Details:
The list will contain many items and I will be removing only some of them.
Inside the loop, I will be doing all sorts of processes, adding, removing etc., so the solution needs to be fairly generic.
The item that I need to delete may not be the current item in the loop. For example, I may be on item 10 of a 30 item loop and need to remove item 6 or item 26. Walking backwards through the array will no longer work because of this. ;o(
The best solution is usually to use the RemoveAll() method:
myList.RemoveAll(x => x.SomeProp == "SomeValue");
Or, if you need certain elements removed:
MyListType[] elems = new[] { elem1, elem2 };
myList.RemoveAll(x => elems.Contains(x));
This assume that your loop is solely intended for removal purposes, of course. If you do need to additional processing, then the best method is usually to use a for or while loop, since then you're not using an enumerator:
for (int i = myList.Count - 1; i >= 0; i--)
{
// Do processing here, then...
if (shouldRemoveCondition)
{
myList.RemoveAt(i);
}
}
Going backwards ensures that you don't skip any elements.
Response to Edit:
If you're going to have seemingly arbitrary elements removed, the easiest method might be to just keep track of the elements you want to remove, and then remove them all at once after. Something like this:
List<int> toRemove = new List<int>();
foreach (var elem in myList)
{
// Do some stuff
// Check for removal
if (needToRemoveAnElement)
{
toRemove.Add(elem);
}
}
// Remove everything here
myList.RemoveAll(x => toRemove.Contains(x));
If you must both enumerate a List<T> and remove from it then I suggest simply using a while loop instead of a foreach
var index = 0;
while (index < myList.Count) {
if (someCondition(myList[index])) {
myList.RemoveAt(index);
} else {
index++;
}
}
I know this post is old, but I thought I'd share what worked for me.
Create a copy of the list for enumerating, and then in the for each loop, you can process on the copied values, and remove/add/whatever with the source list.
private void ProcessAndRemove(IList<Item> list)
{
foreach (var item in list.ToList())
{
if (item.DeterminingFactor > 10)
{
list.Remove(item);
}
}
}
When you need to iterate through a list and might modify it during the loop then you are better off using a for loop:
for (int i = 0; i < myIntCollection.Count; i++)
{
if (myIntCollection[i] == 42)
{
myIntCollection.Remove(i);
i--;
}
}
Of course you must be careful, for example I decrement i whenever an item is removed as otherwise we will skip entries (an alternative is to go backwards though the list).
If you have Linq then you should just use RemoveAll as dlev has suggested.
As you enumerate the list, add the one you want to KEEP to a new list. Afterward, assign the new list to the myIntCollection
List<int> myIntCollection=new List<int>();
myIntCollection.Add(42);
List<int> newCollection=new List<int>(myIntCollection.Count);
foreach(int i in myIntCollection)
{
if (i want to delete this)
///
else
newCollection.Add(i);
}
myIntCollection = newCollection;
Let's add you code:
List<int> myIntCollection=new List<int>();
myIntCollection.Add(42);
myIntCollection.Add(12);
myIntCollection.Add(96);
myIntCollection.Add(25);
If you want to change the list while you're in a foreach, you must type .ToList()
foreach(int i in myIntCollection.ToList())
{
if (i == 42)
myIntCollection.Remove(96);
if (i == 25)
myIntCollection.Remove(42);
}
For those it may help, I wrote this Extension method to remove items matching the predicate and return the list of removed items.
public static IList<T> RemoveAllKeepRemoved<T>(this IList<T> source, Predicate<T> predicate)
{
IList<T> removed = new List<T>();
for (int i = source.Count - 1; i >= 0; i--)
{
T item = source[i];
if (predicate(item))
{
removed.Add(item);
source.RemoveAt(i);
}
}
return removed;
}
How about
int[] tmp = new int[myIntCollection.Count ()];
myIntCollection.CopyTo(tmp);
foreach(int i in tmp)
{
myIntCollection.Remove(42); //The error is no longer here.
}
If you're interested in high performance, you can use two lists. The following minimises garbage collection, maximises memory locality and never actually removes an item from a list, which is very inefficient if it's not the last item.
private void RemoveItems()
{
_newList.Clear();
foreach (var item in _list)
{
item.Process();
if (!item.NeedsRemoving())
_newList.Add(item);
}
var swap = _list;
_list = _newList;
_newList = swap;
}
Just figured I'll share my solution to a similar problem where i needed to remove items from a list while processing them.
So basically "foreach" that will remove the item from the list after it has been iterated.
My test:
var list = new List<TempLoopDto>();
list.Add(new TempLoopDto("Test1"));
list.Add(new TempLoopDto("Test2"));
list.Add(new TempLoopDto("Test3"));
list.Add(new TempLoopDto("Test4"));
list.PopForEach((item) =>
{
Console.WriteLine($"Process {item.Name}");
});
Assert.That(list.Count, Is.EqualTo(0));
I solved this with a extension method "PopForEach" that will perform a action and then remove the item from the list.
public static class ListExtensions
{
public static void PopForEach<T>(this List<T> list, Action<T> action)
{
var index = 0;
while (index < list.Count) {
action(list[index]);
list.RemoveAt(index);
}
}
}
Hope this can be helpful to any one.
Currently you are using a list. If you could use a dictionary instead, it would be much easier. I'm making some assumptions that you are really using a class instead of just a list of ints. This would work if you had some form of unique key. In the dictionary, object can be any class you have and int would be any unique key.
Dictionary<int, object> myIntCollection = new Dictionary<int, object>();
myIntCollection.Add(42, "");
myIntCollection.Add(12, "");
myIntCollection.Add(96, "");
myIntCollection.Add(25, "");
foreach (int i in myIntCollection.Keys)
{
//Check to make sure the key wasn't already removed
if (myIntCollection.ContainsKey(i))
{
if (i == 42) //You can test against the key
myIntCollection.Remove(96);
if (myIntCollection[i] == 25) //or you can test against the value
myIntCollection.Remove(42);
}
}
Or you could use
Dictionary<myUniqueClass, bool> myCollection; //Bool is just an empty place holder
The nice thing is you can do anything you want to the underlying dictionary and the key enumerator doesn't care, but it also doesn't update with added or removed entries.

For Each Loop Not Working When Removing Items From ListBox

why can not i use foreach loop to drop items from listbox:
protected void btnRemove_Click(object sender, EventArgs e)
{
ListBox listbox = Controltest2.FindControl("ListBox1") as ListBox;
if (Controltest2.Items.Count > 0)
{
foreach (ListItem li in listbox.Items)
{
if (li.Selected)
{
Controltest2.Remove(li.Value);
}
}
}
}
This codes give me error to drop item from listbox. On the other hand;
ListBox listbox = Controltest2.FindControl("ListBox1") as ListBox;
if (Controltest2.Items.Count > 0)
{
int count = Controltest2.Items.Count;
for (int i = count - 1; i > -1; i--)
{
if (listbox.Items[i].Selected)
{
Controltest2.Remove(listbox.Items[i].Value);
}
}
}
Why cannot i use "Foreach loop" instead of "for loop"...
The foreach statement repeats a group of embedded statements for each element in an array or an object collection. The foreach statement is used to iterate through the collection to get the desired information, but should not be used to change the contents of the collection to avoid unpredictable side effects
Source: MSDN foreach
Note: emphasis mine
When you use the foreach loop, you are modifying the underlying collection, thereby interupting the enumerator so to speak. If you want to use the foreach loop, try the following:
foreach (ListItem li in listbox.Items.ToArray())
{
if (li.Selected)
{
Controltest2.Remove(li.Value);
}
}
Note: the call to ToArray() in this example assumes LINQ to object and depending on the situation, you may be required to also call the Cast<T>() prior to calling it. The main point that I am trying to get across here is that by creating an array, the foreach is now iterating over the array's enumerator instead of the ListBox's enumerator, allowing you to modify the ListBox's collection at will.
Short answer: When you iterate over a loop using foreach, you can't add or remove items being looped over
In the first example, you're removing items from the start of the collection, which affects the collection which defines the conditions of the iteration, whereas in the second case, you're removing items from the end of the collection each time, and the loop initial conditions are unaffected because of the fixed value of int count.

Categories

Resources