Обзор вопросов по языка програмиированию C# и технологии NET
Реализуется через интерфейсы:
IEnumerable<T> — предоставляет GetEnumerator()IEnumerator<T> — предоставляет Current и MoveNext()IEnumerable<T>public interface IEnumerable<out T>
{
IEnumerator<T> GetEnumerator();
}
IEnumerator<T>public interface IEnumerator<out T> : IDisposable
{
T Current { get; }
bool MoveNext();
void Reset(); // редко используется
}
yield returnyield return позволяет создавать итератор без ручной реализации IEnumerator.IEnumerable<int> GetNumbers()
{
for (int i = 0; i < 5; i++)
yield return i;
}
Особенности:
IEnumerator<T>.var numbers = GetNumbers(); // метод ещё не выполняется
foreach(var n in numbers) // тут начинается генерация
Console.WriteLine(n);
Преимущества:
Минусы:
yield breakIEnumerable<int> NumbersUpTo(int max)
{
for (int i = 0; i < max; i++)
{
if (i == 3)
yield break; // завершение итератора
yield return i;
}
}
Deferred vs Immediate
yield return → deferred.ToList() → immediate.Многоэтапные итераторы
yield return в условных блоках, каждый поддерживает своё состояние.Изменение коллекции во время итерации
InvalidOperationException (для большинства коллекций, кроме Concurrent).Lazy evaluation
IEnumerator.Dispose()
foreach использует try-finally).Структурные итераторы
struct для уменьшения накладных расходов на GC.Несколько foreach на одном IEnumerable
IEnumerable<int> FilterAndSquare(IEnumerable<int> numbers)
{
foreach (var n in numbers)
{
if (n % 2 == 0)
yield return n * n; // только чётные возводим в квадрат
}
}
FilterAndSquare(list) не выполнит ничего, пока не начнётся foreach.Select, Where) возвращают **IEnumerablevar evens = numbers.Where(n => n % 2 == 0); // ещё не выполняется
foreach(var n in evens)
Console.WriteLine(n); // здесь выполнение
Вопросы:
ToList(), Count(), Sum())yield return vs обычный List
IEnumerator vs IEnumerable
IEnumerable предоставляет enumerator, который делает фактический перебор.Можно ли использовать yield return в асинхронных методах?
IAsyncEnumerable<T> и await foreach.Как устроен внутренний state machine компилятора для yield return?
Почему foreach вызывает Dispose?
| Характеристика | IEnumerable |
IEnumerator |
yield return |
|---|---|---|---|
| Кто предоставляет | Коллекция | Перебор | Компилятор создаёт enumerator |
| Deferred execution | Да | Нет | Да |
| Dispose | Нет | Да | Да (через enumerator) |
| Много переборов | Да | Один | Да, каждый GetEnumerator новый |
| Сложность реализации | Нужно вручную | Нужно вручную | Очень просто, компилятор генерирует класс |
✨Dvurechensky✨