2015-10-04 5 views
13

Ho affrontato uno strano problema. Qui ho riprodotto il problema.IEnumerable repeats function

Random r = new Random(); 
List<int> x = new List<int> {1, 2, 3, 4, 5, 6}; 

var e = x.OrderBy(i => r.Next()); 
var list1 = e.ToList(); 
var list2 = e.ToList(); 

bool b = list1.SequenceEqual(list2); 
Console.WriteLine(b); // prints false 

Fino ad ora, ho pensato che le funzioni di Linq venissero eseguite quando vengono chiamate. Ma, con questo metodo, dopo aver chiamato lo ToList, la funzione Linq OrderBy viene eseguita nuovamente. Perchè è così?

+5

Vedere [Esecuzione query] (https://msdn.microsoft.com/en-us/library/vstudio/bb738633 (v = vs.100) .aspx): "Le query LINQ vengono sempre eseguite quando la variabile di query è ripetuto su, non quando viene creata la variabile di query. Si chiama esecuzione differita. " –

+0

@Idle_Mind È necessario aggiungere che questa è la documentazione per * l'esecuzione differita. * Non tutti i metodi LINQ vengono eseguiti in fase di iterazione. –

risposta

19

Stai guardando un'esecuzione differita. Quando si crea una query LINQ, si tratta fondamentalmente di un progetto che dice "quando richiesto, eseguire questi passaggi per manipolare l'origine dati". La parte difficile è che questa richiesta viene eseguita solo da un insieme distinto di operazioni LINQ (.ToList() è uno di questi).

Quindi quando si chiama e.ToList() una volta randomizzare l'origine dati perché è quello che il piano dice che deve fare. Quando poi chiami di nuovo .ToList() su questo stesso progetto, ricomincia dall'inizio e si randomizza di nuovo.

Un progetto non contiene nessuno stato, dice solo cosa dovrebbe essere fatto in ogni fase del percorso.

+5

Per essere precisi: LINQ utilizza l'esecuzione posticipata ove possibile. Per 'OrderBy' o' Where' viene valutato solo su richiesta (ad esempio tramite la chiamata a 'ToList'). Per gli altri, come 'Count' o' Sum', viene eseguito immediatamente. –

+1

@DanielRose Fondamentalmente, ove possibile, LINQ utilizzerà l'esecuzione differita. Ad esempio, puoi contare o sommare senza iterare comunque l'intera collezione. –

+3

@YuvalItzchakov non puoi contare o sommare senza ripetere l'intera collezione; è quello che intendevi, vero? – Martijn