I tried this earlier today:
public interface IFoo
{
IEnumerable GetItems_A( ref int somethingElse );
IEnumerable GetItems_B( ref in
If you want to return both an iterator and an int from your method, a workaround is this:
public class Bar : IFoo
{
public IEnumerable GetItems( ref int somethingElse )
{
somethingElse = 42;
return GetItemsCore();
}
private IEnumerable GetItemsCore();
{
yield return 7;
}
}
You should note that none of the code inside an iterator method (i.e. basically a method that contains yield return
or yield break
) is executed until the MoveNext()
method in the Enumerator is called. So if you were able to use out
or ref
in your iterator method, you would get surprising behavior like this:
// This will not compile:
public IEnumerable GetItems( ref int somethingElse )
{
somethingElse = 42;
yield return 7;
}
// ...
int somethingElse = 0;
IEnumerable items = GetItems( ref somethingElse );
// at this point somethingElse would still be 0
items.GetEnumerator().MoveNext();
// but now the assignment would be executed and somethingElse would be 42
This is a common pitfall, a related issue is this:
public IEnumerable GetItems( object mayNotBeNull ){
if( mayNotBeNull == null )
throw new NullPointerException();
yield return 7;
}
// ...
IEnumerable items = GetItems( null ); // <- This does not throw
items.GetEnumerators().MoveNext(); // <- But this does
So a good pattern is to separate iterator methods into two parts: one to execute immediately and one that contains the code that should be lazily executed.
public IEnumerable GetItems( object mayNotBeNull ){
if( mayNotBeNull == null )
throw new NullPointerException();
// other quick checks
return GetItemsCore( mayNotBeNull );
}
private IEnumerable GetItemsCore( object mayNotBeNull ){
SlowRunningMethod();
CallToDatabase();
// etc
yield return 7;
}
// ...
IEnumerable items = GetItems( null ); // <- Now this will throw
EDIT:
If you really want the behavior where moving the iterator would modify the ref
-parameter, you could do something like this:
public static IEnumerable GetItems( Action setter, Func getter )
{
setter(42);
yield return 7;
}
//...
int local = 0;
IEnumerable items = GetItems((x)=>{local = x;}, ()=>local);
Console.WriteLine(local); // 0
items.GetEnumerator().MoveNext();
Console.WriteLine(local); // 42