Perché dovrei usare ListT su IEnumerableT?

22

Nella mia applicazione web ASP.net MVC4 utilizzo IEnumerables, cercando di seguire il mantra per programmare l'interfaccia, non l'implementazione.

Return IEnumerable(Of Student)

vs

Return New List(Of Student)

Le persone mi dicono di usare List e non IEnumerable, perché gli elenchi costringono la query a essere eseguita e IEumerable no.

Questa è davvero una buona pratica? C'è qualche alternativa? Mi sento strano usando oggetti concreti dove un'interfaccia potrebbe essere usata. Il mio strano sentimento è giustificato?

    
posta Rowan Freeman 06.04.2013 - 05:15
fonte

3 risposte

20

Ci sono momenti in cui fare un ToList() sulle query di linq può essere importante per garantire che le query vengano eseguite al momento e nell'ordine in cui ci si aspetta che lo facciano. Questi scenari sono tuttavia rari e non bisogna preoccuparsi troppo di nulla finché non li incontrano veramente.

Per farla breve, usa IEnumerable ogni volta che hai bisogno dell'iterazione, usa IList quando devi indicizzare direttamente e hai bisogno di un array di dimensioni dinamiche (se hai bisogno di indicizzazione su una matrice di dimensioni fisse, usa solo un array standard) .

Per quanto riguarda il tempo di esecuzione, puoi sempre usare un elenco come variabile IEnumerable , quindi sentiti libero di restituire un IEnumerable facendo un .ToList(); , o passa un parametro come IEnumerable di eseguendo .ToList() su IEnumerable per forzare l'esecuzione giusto allora e lì. Fai attenzione che ogni volta che imposti l'esecuzione con .ToList() non ti blocchi alla variabile IEnumerable che hai appena fatto e l'esegui di nuovo, altrimenti finirai per raddoppiare le iterazioni nella tua query LINQ inutilmente .

Riguardo a MVC, non c'è davvero nulla di speciale da notare qui. Seguirà le stesse regole del tempo di esecuzione del resto di .NET, penso che potresti avere qualcuno che era un po 'confuso causato dalla semantica di esecuzione ritardata in passato e lo ha incolpato su MVC dicendoti che questo è in qualche modo correlato, ma è non. La semantica di esecuzione ritardata confonde tutti all'inizio (e anche per un po 'di tempo dopo, possono essere un po' complicati). Ancora una volta, però, non preoccuparti di ciò finché non ti preoccupi veramente di garantire che una query LINQ non venga eseguita due volte o richieda che venga eseguita in un certo ordine rispetto ad un altro codice, a quel punto assegna la tua variabile a se stessa.ToList () forzare l'esecuzione e starai bene.

    
risposta data 06.04.2013 - 05:52
fonte
7

Ci sono due problemi.

IENumerable<Data> query = MyQuery();

//Later
foreach (Data item in query) {
  //Process data
}

Quando viene raggiunto il ciclo "Process Data", la query potrebbe non essere più valida. Ad esempio, se la query viene eseguita su un DataContext che è già stato eliminato, il codice genererà un'eccezione. Questo tipo di cose diventa molto confuso quando si elabora una query in un contesto diverso da quello in cui è stata creata.

Un problema secondario è che la connessione non verrà rilasciata fino al completamento del ciclo "Dati processo". Questo è solo un problema se "Dati di processo" è complesso. Questo è citato al link :

Q. How long does my database connection remain open?

A. A connection typically remains open until you consume the query results. If you expect to take time to process all the results and are not opposed to caching the results, apply ToList to the query. In common scenarios where each object is processed only one time, the streaming model is superior in both DataReader and LINQ to SQL.

Pertanto, questi problemi spiegano perché sei incoraggiato a garantire che la query sia effettivamente eseguita, ad es. chiamando ToList() . Tuttavia, come Jimmy Suggests non c'è nulla che ti impedisca di restituire il tuo Elenco come IEnumerable.

Come regola generale, consiglio di evitare di scorrere su un oggetto IEnumerable più di una volta. Supponendo che i consumatori del tuo codice seguano questa regola, non considero che qualcuno possa colpire il database due volte eseguendo la query due volte.

    
risposta data 06.04.2013 - 06:10
fonte
1

Un altro vantaggio dell'enumerazione precoce di IEnumerable è che le eccezioni verranno generate nella posizione appropriata. Questo aiuta il debug.

Ad esempio, se hai ottenuto un'eccezione deadlock all'interno di una delle tue visualizzazioni Razor, non sarebbe davvero così chiaro come se si fosse verificata un'eccezione durante uno dei tuoi metodi di accesso ai dati.

    
risposta data 03.11.2013 - 22:57
fonte