Se si desidera restituire sia un iteratore e un int dal tuo metodo, una soluzione è questa:
public class Bar : IFoo
{
public IEnumerable<int> GetItems(ref int somethingElse)
{
somethingElse = 42;
return GetItemsCore();
}
private IEnumerable<int> GetItemsCore();
{
yield return 7;
}
}
Si dovrebbe notare che nessuno di codice all'interno di un Il metodo iteratore (ovvero un metodo che contiene yield return
o yield break
) viene eseguito finché non viene chiamato il metodo MoveNext()
nell'enumeratore. Quindi, se tu fossi in grado di utilizzare out
o ref
nel metodo iteratore, si otterrebbe un comportamento sorprendente come questo:
// 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
Questo è un errore comune, un problema correlato è questo:
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
Così un buon modello è quello di separare i metodi di iteratore in due parti: una da eseguire immediatamente e una che contiene il codice che deve essere eseguito pigramente.
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: Se si vuole veramente il comportamento in cui si muove l'iteratore modificherebbe il ref
-parameter, si potrebbe fare qualcosa di simile:
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
fonte
2009-06-16 08:02:04
È successo qualcosa quando hai provato questo, o ci stai chiedendo il tuo fondamento logico per provarlo? –
Discuto di alcune di queste considerazioni sulla progettazione qui: http://blogs.msdn.com/ericlippert/archive/2009/05/04/the-stack-is-an-implementation-detail-part-two.aspx –
soluzione moderna : http://answers.unity3d.com/answers/551381/view.html – Fattie