Search code examples
c#garbage-collectionheap-memoryienumerableenumerator

Does the use of an iterator imply a heap object?


Does the creation of an object of type IEnumerable<T> (such as the numbers object of type IEnumerable<int> in the below code example) imply the creation of an object on the heap that has finally to be garbage-collected?

Consider for example the following iterator as described in this blog post

IEnumerable<int> GetOneTwoThree() {
  yield return 1;
  yield return 2;
  yield return 3;
}

and then its usage with

var numbers = GetOneTwoThree();

foreach (var number in numbers) {
  Console.WriteLine(number);
}

Solution

  • imply the creation of an object on the heap that has finally to be garbage-collected?

    Short answer: Yes, in this case

    Apart from anything else: the moment you're implementing IEnumerable<T>, that means your iterator is typed as IEnumerator<T>, so even if it was actually being implemented in a value-type: it will be boxed (thus: a heap allocation) when typed as the interface.


    Longer answer: it is possible to write hand written iterators that use struct (or even ref struct), which then may be used without any heap allocation - as long as the type is used explicitly rather than via the IEnumerable<T>/IEnumerator<T> interfaces - List<T> is an example of this, with a custom value-type iterator. However, that precludes the use of yield return - it must be hand written. Fortunately foreach is duck-typed, so can make efficient use of such custom iterators (when the GetEnumerator() method returns something bespoke that has the required features).