A List<T> internally holds its "version" in an integer variable. Each modification to the list (Add, Remove, Sort, Clear, ...) increments this version by one.
Now the enumerator for a List<T>, when initialized, saves this version number. Upon every MoveNext(), i.e. on every iteration, it checks whether the list's version number still equals the saved version number.
This way it can detect when a list is modified between two iterations. Note this implementation causes a peculiar bug with integer overflow: Why this code throws 'Collection was modified', but when I iterate something before it, it doesn't?.
There also appears to be a bug regarding Sort(Comparison<T> comparison), which doesn't increment the version number. This code:
var list = new List<string>
{
"foo",
"bar",
};
foreach (var l in list)
{
Console.WriteLine(l);
list.Sort((x, y) => x.CompareTo(y));
}
Prints:
foo
foo