Если вы хотите вернуть итератор и int из вашего метода, обходной путь:
public class Bar : IFoo
{
public IEnumerable<int> GetItems( ref int somethingElse )
{
somethingElse = 42;
return GetItemsCore();
}
private IEnumerable<int> GetItemsCore();
{
yield return 7;
}
}
Следует отметить, что ни один из кодов внутри метода итератора (т. Е. В основном метод, содержащий yield return
или yield break
) не выполняется до тех пор, пока не будет вызван метод MoveNext()
в перечислителе. Поэтому, если бы вы могли использовать out
или ref
в своем методе итератора, вы бы получили удивительное поведение, подобное этому:
// This will not compile:
public IEnumerable<int> GetItems( ref int somethingElse )
{
somethingElse = 42;
yield return 7;
}
// ...
int somethingElse = 0;
IEnumerable<int> 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
Это распространенная ошибка, связанная с этим проблема:
public IEnumerable<int> GetItems( object mayNotBeNull ){
if( mayNotBeNull == null )
throw new NullPointerException();
yield return 7;
}
// ...
IEnumerable<int> items = GetItems( null ); // <- This does not throw
items.GetEnumerators().MoveNext(); // <- But this does
Таким образом, хорошим примером является разделение методов итератора на две части: одну для немедленного выполнения и другую, содержащую код, который должен выполняться лениво.
public IEnumerable<int> GetItems( object mayNotBeNull ){
if( mayNotBeNull == null )
throw new NullPointerException();
// other quick checks
return GetItemsCore( mayNotBeNull );
}
private IEnumerable<int> GetItemsCore( object mayNotBeNull ){
SlowRunningMethod();
CallToDatabase();
// etc
yield return 7;
}
// ...
IEnumerable<int> items = GetItems( null ); // <- Now this will throw
EDIT:
Если вам действительно нужно поведение, при котором перемещение итератора приведет к изменению ref
-параметра, вы можете сделать что-то вроде этого:
public static IEnumerable<int> GetItems( Action<int> setter, Func<int> getter )
{
setter(42);
yield return 7;
}
//...
int local = 0;
IEnumerable<int> items = GetItems((x)=>{local = x;}, ()=>local);
Console.WriteLine(local); // 0
items.GetEnumerator().MoveNext();
Console.WriteLine(local); // 42