2009-09-24 12 views
6
using System; 
using System.Collections.Generic; 
using System.Text; 
using System.Collections; 

namespace ConsoleApplication4 
{ 
    class Program 
    { 
     static void Main (string[] args) 
     { 
      var test1 = Test1(1, 2); 
      var test2 = Test2(3, 4); 
     } 

     static IEnumerable Test1(int v1, int v2) 
     { 
      yield break; 
     } 

     static IEnumerable Test2 (int v1, int v2) 
     { 
      return new String[] { }; 
     } 
    } 
} 

"test1" sembra essere un IEnumerable con v1 e v2 (params) come campi e "Test1" NON viene chiamato.intervallo di rendimento; - comportamento pazzo

"Test2" lavora "disegnato" :)

cosa sta succedendo?

risposta

15

Test1è chiamato, ma a meno di eseguire iterazioni attraverso il risultato, non si ha colpito un punto di interruzione yield break.

Fondamentalmente Test1 si trasforma in una macchina a stati che implementa IEnumerable per voi ... ma tutto il corpo del metodo è dentro quella macchina dello stato, e se non si utilizza la macchina dello Stato chiamando GetEnumerator() e poi MoveNext() (o usando un ciclo foreach) non vedrai il tuo corpo eseguire.

Vedi il mio general iterator article e la mia iterator implementation articolo per ulteriori informazioni, e anche due dei post del blog di Eric Lippert: Psychic Debugging part one e Psychic Debugging part two.

1

Dato che hai citato Python, farò notare che i generatori in Python funzionano in modo simile ai generatori in C#. C'è solo la piccola differenza che il solo yield break può trasformare un metodo C# in un generatore, mentre l'equivalente Python di raise StopIteration no.

>>> def f(): 
...  print "Beginning of generator" 
...  if False: yield 
...  print "End of generator" 
... 
>>> it = f() 
>>> it 
<generator object at 0x94fae2c> 
>>> it.next() 
Beginning of generator 
End of generator 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
StopIteration