Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
Why the error Collection was modified; enumeration operation may not execute occurs and how to handle it in C#?
This error occurs when you modify a collection (such as adding or removing items) while iterating through it with a foreach loop or enumerator. The .NET runtime throws this exception to prevent unpredictable behavior and maintain collection integrity.
Why This Error Occurs
When you use foreach, it creates an internal enumerator that tracks the collection's state. If the collection is modified during iteration, the enumerator detects this change and throws an InvalidOperationException to prevent data corruption or infinite loops.
Example Demonstrating the Error
The following example shows how this error occurs when removing items during iteration −
using System;
using System.Collections.Generic;
namespace DemoApplication {
public class Program {
static void Main(string[] args) {
try {
var studentsList = new List<Student> {
new Student {
Id = 1,
Name = "John"
},
new Student {
Id = 0,
Name = "Jack"
},
new Student {
Id = 2,
Name = "Jane"
}
};
foreach (var student in studentsList) {
if (student.Id <= 0) {
studentsList.Remove(student);
}
else {
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
}
}
}
catch(Exception ex) {
Console.WriteLine($"Exception: {ex.Message}");
}
}
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
}
}
The output of the above code is −
Id: 1, Name: John Exception: Collection was modified; enumeration operation may not execute.
Solution Methods
Using ToList() to Create a Copy
Create a snapshot of the collection using ToList() before iteration. This allows you to modify the original collection safely −
using System;
using System.Collections.Generic;
using System.Linq;
namespace DemoApplication {
public class Program {
static void Main(string[] args) {
var studentsList = new List<Student> {
new Student {
Id = 1,
Name = "John"
},
new Student {
Id = 0,
Name = "Jack"
},
new Student {
Id = 2,
Name = "Jane"
}
};
foreach (var student in studentsList.ToList()) {
if (student.Id <= 0) {
studentsList.Remove(student);
}
else {
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
}
}
Console.WriteLine($"Remaining students: {studentsList.Count}");
}
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
}
}
The output of the above code is −
Id: 1, Name: John Id: 2, Name: Jane Remaining students: 2
Using RemoveAll() Method
For removal scenarios, use the RemoveAll() method which is designed to handle modifications safely −
using System;
using System.Collections.Generic;
namespace DemoApplication {
public class Program {
static void Main(string[] args) {
var studentsList = new List<Student> {
new Student { Id = 1, Name = "John" },
new Student { Id = 0, Name = "Jack" },
new Student { Id = 2, Name = "Jane" },
new Student { Id = -1, Name = "Invalid" }
};
Console.WriteLine("Before removal:");
foreach (var student in studentsList) {
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
}
int removedCount = studentsList.RemoveAll(s => s.Id <= 0);
Console.WriteLine($"\nRemoved {removedCount} students");
Console.WriteLine("After removal:");
foreach (var student in studentsList) {
Console.WriteLine($"Id: {student.Id}, Name: {student.Name}");
}
}
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
}
}
The output of the above code is −
Before removal: Id: 1, Name: John Id: 0, Name: Jack Id: 2, Name: Jane Id: -1, Name: Invalid Removed 2 students After removal: Id: 1, Name: John Id: 2, Name: Jane
Using For Loop (Reverse Iteration)
When removing items, iterate backwards using a traditional for loop to avoid index shifting issues −
using System;
using System.Collections.Generic;
namespace DemoApplication {
public class Program {
static void Main(string[] args) {
var studentsList = new List<Student> {
new Student { Id = 1, Name = "John" },
new Student { Id = 0, Name = "Jack" },
new Student { Id = 2, Name = "Jane" }
};
for (int i = studentsList.Count - 1; i >= 0; i--) {
if (studentsList[i].Id <= 0) {
Console.WriteLine($"Removing: {studentsList[i].Name}");
studentsList.RemoveAt(i);
}
else {
Console.WriteLine($"Keeping: Id: {studentsList[i].Id}, Name: {studentsList[i].Name}");
}
}
Console.WriteLine($"Final count: {studentsList.Count}");
}
}
public class Student {
public int Id { get; set; }
public string Name { get; set; }
}
}
The output of the above code is −
Keeping: Id: 2, Name: Jane Removing: Jack Keeping: Id: 1, Name: John Final count: 2
Best Practices
| Scenario | Recommended Solution | Performance |
|---|---|---|
| Removing items based on condition | RemoveAll() method | Best |
| Complex modifications during iteration | ToList() copy | Good |
| Index-based removal | Reverse for loop | Good |
| Adding items during iteration | Collect items, add after loop | Best |
Conclusion
The "Collection was modified" error protects against data corruption during iteration. Use RemoveAll() for conditional removal, ToList() for complex modifications, or reverse iteration for index-based operations. Choose the method that best fits your specific use case for optimal performance and code clarity.
