Это пример шаблона Non-Virtual Interface (аналогично Template Method ). Это шаблон, используемый в языках с множественным (реализационным) наследованием, и способ сделать это в C # - использовать методы расширения.
Основная идея заключается в том, что у вас есть только не виртуальные и чисто виртуальные (абстрактные) методы. Разработчик интерфейса (или наследник класса / mixin в языках с множественным наследованием) реализует небольшой метод или набор методов (в данном случае, GetEnumerator), а взамен получает целый ряд методов, которые зависят от этого. один абстрактный метод (например, Select, Where, Aggregate и т. д.)
Как сказал Майкл Иденфилд в своем ответе, если мы хотим внедрить этот шаблон и хотим, чтобы IEnumerable был интерфейсом, нам нужно использовать методы расширения. И делать IEnumerable в абстрактном классе было бы плохо, потому что он должен быть очень дешевым, базовым интерфейсом, который должен быть встроен практически в любую коллекцию - реализация IEnumerable не должна требовать переосмысления иерархии классов, она должна быть почти «бесплатной» ».