Occasionally you may encounter a need to delete list items from a SharePoint list. This sounds like an easy enough task – just loop through the SPList’s Items collection and delete the item. That would be the intuitive way, but then again this is the SharePoint Object Model. Let’s take a look a bunch of ways you may try to accomplish this task, and a single way which actually works.
To run these tests, I created a simple custom list named Widgets that contains 10 items:
Incorrect Method #1
The first approach that is probably taken is to loop through the list items with a For..Each loop, and call the Delete() method of each list item, like the following:
using (SPSite siteCollection = new SPSite("http://server")) {
using (SPWeb site = siteCollection.OpenWeb()) {
SPList list = site.Lists["Widgets"];
foreach (SPListItem item in list.Items) {
item.Delete();
}
}
}
However, whenever you run this you encounter the following error:
Collection was modified; enumeration operation may not execute.
To help explain this, it will help to first understand the IEnumerable interface, from with the SPListItemCollection ultimately implements. Unfortunately the MSDN documentation is a little scarce on modifying collections with this interface, but the IEnumerator interface contains a lot of good information that applies to IEnumerable as well.
Basically, enumerators can be used to read the data in the collection, but they cannot be used to modify the underlying collection. An enumerator remains valid as long as the collection remains unchanged. If changes are made to the collection (such as deleting), the enumerator is irrecoverably invalidated.
Incorrect Method #2
Ok, learning from the mistake in method 1, it makes sense to eliminate the For..Each loop and use a traditional For loop. This method uses an index which increments at each loop, and we call the Delete(index) method of the list item which accepts an item index:
for (int i = 0; i < list.Items.Count; i++) {
Console.WriteLine("Deleting {0}", list.Items[i].Title);
list.Items.Delete(i);
}
To visualize the results, I’m outputting the item it’s deleting so we can see if everything is working as it should:
What the heck is happening here? Why is it deleting every other item? Well, every time you delete an item from the Items collection, the number of items in that collection decreases and thus the indexes no longer match up.
Incorrect Method #3
Hmm, OK…if it’s deleting every other item because the collection is adjusted when items are deleted from it, let’s just be safe and always try to delete the first item at index 0:
for (int i = 0; i < list.Items.Count; i++) {
Console.WriteLine("Deleting {0}", list.Items[0].Title);
list.Items.Delete(0);
}
The result is exactly like Method #2 – it deletes every other item:
Incorrect Method #4
For kicks and giggles, what if the code is adjusted to delete the item at index 0 inside a For..Each loop?:
foreach (SPListItem item in list.Items) {
Console.WriteLine("Deleting {0}", list.Items[0].Title);
list.Items.Delete(0);
}
Woah, that worked! As you can see, it deleted every item:
But wait… What if we need to delete an item only if a condition is met? Let’s try to loop through the collection and only delete the item whose title is Sample Item #5:
foreach (SPListItem item in list.Items) {
if (item.Title == "Sample Item 5") {
Console.WriteLine("Deleting {0}", list.Items[0].Title);
list.Items.Delete(0);
}
}
The result is what you should expect after deleting the first item in the index – it deletes the first item, not the item that met the condition:
Correct Method
Ok, finally here’s the correct method for deleting list items. The trick is to use a decrementing For loop. The For loop in the following example counts downward (i–) instead of upward (i++), because items are being deleted and the number of items decreases with each increment:
for (int i = list.Items.Count - 1; i >= 0; i--) {
list.Items.Delete(i);
}
Which produces:
What about deleting an item based on a condition?:
for (int i = list.Items.Count - 1; i >= 0; i--) {
if (list.Items[i].Title == "Sample Item 5") {
Console.WriteLine("Deleting {0}", list.Items[i].Title);
list.Items.Delete(i);
}
}
It works!:
Hopefully you will always remember to delete list items (actually, the same goes for most other SharePoint collections too, such as SPFieldCollection, SPWebCollection, etc.) using a decrementing counter. Happy coding!