The point of an iterator is to return an enumerable list of items one at a time. To understand the "one at a time" part and why it's useful, consider the Directory.GetFiles
and Directory.EnumerateFiles
methods being used to search your hard drive for a file with particular properties. The GetFiles
method will get the path of every file in a folder first, put them all into an array and return that. That might take some time to do, and it might be that you find a matching file very early in that array, in which case a lot of time and effort was wasted getting the rest of the files. The EnumerateFiles
method, on the other hand, will return the path of a file as it is available. That means that there is very little wait to be able to start processing the files and, if you find a match and stop the enumeration, no more file paths will be retrieved. In situations like this, the iterator's "one at a time" approach means less waiting and possibly less work.
The point of the yield return
statement is to return one item. Using it to return an array makes no sense, unless your method returns an enumerable list of arrays. In the previous example, GetFiles
gets all the file paths, puts them into an array and returns that with a return
statement. On the other hand, the EnumerateFiles
methods returns one file path at a time with the yield return
statement. The way iterators work is that, if you have a yield return x;
statement then the return type of the method should generally be IEnumerable<T>
where T
is the type of x
, e.g. if x
is a string
then the method's return type should be IEnumerable<string>
.
The IEnumerable
and IEnumerable<T>
interfaces exist primarily to be used with foreach
loops. Developers will often write a method that returns one of those types if they intend for the result to be enumerated with such a loop. By doing so, it would enable them to change their implementation later to return a different type, e.g. they could implement an iterator instead of returning a concrete list, without breaking any code that calls the method. It also makes the returned list effectively read-only. If such a method returned an array or List<T>
then the caller could modify the list before using it. As an IEnumerable
or IEnumerable<T>
can only be enumerated and not have its items accessed at random, modifying the list is not really possible. You could always determine the actual type of the object at run time and cast or use Reflection or whatever but that is more effort and not so likely to be done mistakenly or smuggled in maliciously.