Как реализовать собственный Where без yield? Что такое yield и как он работает под капотом?
Answer from AI
sobes.tech AI
yield в C# используется в итераторах для ленивой генерации последовательностей. Когда метод с yield return вызывается, он возвращает объект IEnumerable или IEnumerator, который при итерации последовательно возвращает значения, сохраняя состояние между вызовами.
Под капотом компилятор преобразует такой метод в конечный автомат (state machine), который хранит текущее состояние итерации и локальные переменные.
Чтобы реализовать собственный Where без yield, нужно вручную создать класс-итератор, реализующий IEnumerable<T> и IEnumerator<T>. В методе MoveNext будет логика фильтрации.
Пример упрощённой реализации Where без yield:
public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
return new WhereEnumerable<T>(source, predicate);
}
class WhereEnumerable<T> : IEnumerable<T>
{
private IEnumerable<T> _source;
private Func<T, bool> _predicate;
public WhereEnumerable(IEnumerable<T> source, Func<T, bool> predicate)
{
_source = source;
_predicate = predicate;
}
public IEnumerator<T> GetEnumerator() => new WhereEnumerator(_source.GetEnumerator(), _predicate);
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
class WhereEnumerator : IEnumerator<T>
{
private IEnumerator<T> _sourceEnumerator;
private Func<T, bool> _predicate;
public WhereEnumerator(IEnumerator<T> sourceEnumerator, Func<T, bool> predicate)
{
_sourceEnumerator = sourceEnumerator;
_predicate = predicate;
}
public T Current => _sourceEnumerator.Current;
object IEnumerator.Current => Current;
public bool MoveNext()
{
while (_sourceEnumerator.MoveNext())
{
if (_predicate(_sourceEnumerator.Current))
return true;
}
return false;
}
public void Reset() => _sourceEnumerator.Reset();
public void Dispose() => _sourceEnumerator.Dispose();
}
}
Таким образом, yield упрощает написание таких итераторов, скрывая сложность конечного автомата и состояния.