"IEnumerable should not be forced to return a type-erased = heap allocated IEnumerator instance."
Foreach loops use compile-time duck typing, so if you don't intend to use your enumerable in LINQ then both the enumerable and enumerator don't need to implement any interfaces.
This optimisation covers only one common use case, but that's the way of things in C# land.
IEnumerators can also be value types So no heap allocation, just stack.
slightly off topic but a lot of things in .NET actually use compile time duct typing. like how async works To make your own task, you don't add an interface to it. You just implement a single method.