Намагаючись зберегти речі "простими", .NET має лише одну загальну / негенеричну пару інтерфейсів для речей, які перераховуються за допомогою виклику, GetEnumerator()а потім використання MoveNextта Currentотримання об'єкта, отриманого від нього, хоча існує як мінімум чотири види об'єктів який повинен підтримувати лише такі методи:
- Речі, які можна перерахувати хоча б один раз, але не обов'язково більше, ніж це.
- Речі, які можна перераховувати довільно кількість разів у контекстах із безкоштовним потоком, але можуть довільно отримувати різний вміст кожного разу
- Речі, які можна перераховувати довільно кількість разів у контекстах з безкоштовними потоками, але можуть гарантувати, що якщо код, який їх перераховує повторно, не викликає жодних мутуючих методів, усі перерахування повертають однаковий вміст.
- Речі, які можна перераховувати в довільній кількості разів, і гарантовано повертати один і той же вміст кожен раз, поки вони існують.
Будь-який екземпляр, який задовольняє одному з визначень з більшими числами, задовольнятиме також і всі нижчі, але код, для якого потрібен об'єкт, що задовольняє одному з вищих визначень, може порушитися, якщо задати одне з нижчих.
Схоже, Microsoft вирішила, що класи, які реалізують, IEnumerable<T>повинні відповідати другому визначенню, але не зобов'язані задовольняти щось вище. Можливо, існує не так багато причин, що щось, що могло б відповідати лише першому визначенню, має реалізовувати, IEnumerable<T>а не IEnumerator<T>; якщо foreachцикли можуть прийняти IEnumerator<T>, то для речей, які можна перерахувати лише один раз, було б сенсом просто реалізувати останній інтерфейс. На жаль, типи, які реалізуються лише IEnumerator<T>, менш зручні у використанні у C # та VB.NET, ніж типи, у яких є GetEnumeratorметод.
У будь-якому випадку, навіть якщо це було б корисно, якби були різні перелічені типи речей, які могли б дати різні гарантії, та / або стандартний спосіб запитати екземпляр, який реалізує IEnumerable<T>те, що може дати гарантій, таких типів ще не існує.