I tried this earlier today:
public interface IFoo
{
IEnumerable<int> GetItems_A( ref int somethingElse );
IEnumerable<int> GetItems_B( ref int somethingElse );
}
public class Bar : IFoo
{
public IEnumerable<int> GetItems_A( ref int somethingElse )
{
// Ok...
}
public IEnumerable<int> GetItems_B( ref int somethingElse )
{
yield return 7; // CS1623: Iterators cannot have ref or out parameters
}
}
What’s the rationale behind this?
C# iterators are state machines internally. Every time you
yield returnsomething, the place where you left off should be saved along with the state of local variables so that you could get back and continue from there.To hold this state, C# compiler creates a class to hold local variables and the place it should continue from. It’s not possible to have a
reforoutvalue as a field in a class. Consequently, if you were allowed to declare a parameter asreforout, there would be no way to keep the complete snapshot of the function at the time we had left off.EDIT: Technically, not all methods that return
IEnumerable<T>are considered iterators. Just those that useyieldto produce a sequence directly are considered iterators. Therefore, while the splitting the iterator into two methods is a nice and common workaround, it doesn’t contradict with what I just said. The outer method (that doesn’t useyielddirectly) is not considered an iterator.