How to implement your own Where without yield? What is yield and how does it work under the hood?
sobes.tech AI
Answer from AI
yield in C# is used in iterators for lazy generation of sequences. When a method with yield return is called, it returns an IEnumerable or IEnumerator object, which, when iterated, returns values sequentially while maintaining state between calls.
Under the hood, the compiler transforms such a method into a state machine that stores the current iteration state and local variables.
To implement a custom Where without yield, you need to manually create an iterator class that implements IEnumerable<T> and IEnumerator<T>. The MoveNext method will contain the filtering logic.
Here's a simplified example of implementing Where without 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();
}
}
Thus, yield simplifies writing such iterators by hiding the complexity of the state machine and state management.