如果你想从方法中返回迭代器和整数,一个解决方法是:
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
,则可能会出现意外行为,例如:
public IEnumerable<int> GetItems( ref int somethingElse )
{
somethingElse = 42;
yield return 7;
}
int somethingElse = 0;
IEnumerable<int> items = GetItems( ref somethingElse );
items.GetEnumerator().MoveNext();
这是一个常见的陷阱,相关问题是:
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
编辑:
如果您真的希望移动迭代器会修改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);
items.GetEnumerator().MoveNext();
Console.WriteLine(local);