2015-12-10 9 views
10

Stavo leggendo a blog da Eric Lippert dove ha spiegato perché ha quasi mai usare le matrici, e la parte seguente mi ha incuriosito:Qual è l'utilizzo di AsEnumerable() su un array?

Se si sta scrivendo un tale API, avvolgere la matrice in una ReadOnlyCollection e ritorno un oggetto IEnumerable o un IList o qualcosa, ma non un array. (E ovviamente non basta lanciare l'array a IEnumerable e pensare che hai finito! Sta ancora passando le variabili, il chiamante può semplicemente tornare ad array! Solo passare un array se è racchiuso da un sola lettura oggetto)

così ho dovuto vedermela un po 'con le collezioni:.

string[] array = new[] { "cat", "dog", "parrot" }; 
IEnumerable<string> test1 = array.AsEnumerable(); 
string[] secondArray = (string[])test1; 

//array1[0] is now also "whale" 
array[0] = "whale"; 

//11 interfaces 
var iArray = array.GetType().GetInterfaces(); 
//Still 11 interfaces?? 
var iTest1 = test1.GetType().GetInterfaces(); 

ho inizializzare un array e quindi utilizzare il metodo AsEnumerable() su di esso per convertirlo in un IEnumerable (o giù di lì Ho pensato), ma quando lo ricollego a un nuovo array e cambio un valore nell'array originale, i valori di test1 e secondArray cambiato in. A quanto pare ho appena fatto 2 nuovi riferimenti alla matrice originale, invece di creare un nuovo IEnumerable un po 'come ToArray() restituisce un nuovo array.

Quando si confrontano le interfacce dell'array e IEnumerable, entrambi hanno le stesse interfacce. Perché la matrice ha quel metodo se in realtà non fa nulla? So che AsEnumerable() ha i suoi usi con Linq-to-entities per ottenere i metodi enumerabili quando hai un IQueryable, ma perché questo metodo dovrebbe essere aggiunto a un array? Esiste un uso pratico per questo metodo?

Edit: Questo commento di Tim Schmelter solleva un ottimo punto e non deve passare inosservato:

"Non è così inutile È possibile modificare il tipo effettivo senza rompere il resto del codice.. Quindi è possibile sostituire l'array con una query o elenco di database o hashset o altro, ma l'AsEnumerable funziona sempre e anche il resto del codice. Quindi AsEnumerable è come un contratto. "

+0

forse questo può aiutare: il metodo http://stackoverflow.com/questions/2013846/why-use-asenumerable-rather-than-casting-to-ienumerablet – Domysee

+1

'L'AsEnumerable (IEnumerable ) non ha alcun effetto altra piuttosto che modificare il tipo di origine in fase di compilazione da un tipo che implementa IEnumerable in IEnumerable . https://msdn.microsoft.com/library/bb335435(v=vs.100).aspx –

+0

E le implicazioni di Quanto sopra (quello che ho citato) significa che puoi scorrere su di esso diversamente. Non so cos'altro offre. –

risposta

9

AsEnumerable è solo un modo per trasmettere il valore a IEnumerable<T>. Non crea un nuovo oggetto. L'implementazione del metodo è la seguente:

public static IEnumerable<TSource> AsEnumerable<TSource>(this IEnumerable<TSource> source) 
{ 
    return source; 
} 

Non sta creando un nuovo oggetto.

motivi è utile:

  1. Se un oggetto implementa IEnumerable<T> ma ha anche un metodo di istanza denominata Select, Where, ecc, non è possibile utilizzare il metodo LINQ. AsEnumerable consente di trasmetterlo a IEnumerable per evitare tali conflitti di sovraccarico.

  2. Se si vuole lanciare un oggetto IEnumerable<T> (per qualsiasi motivo), ma T è un tipo anonimo, è non può usare un cast, è necessario un metodo generico che può inferire il suo argomento generico per fare esso.

4

Lo scopo di AsEnumerable è chiaro come descritto nel e questo post Servy's answer per esempio: Why use .AsEnumerable() rather than casting to IEnumerable<T>?.

La domanda rimanente è: perché è visibile su IEnumerable<T>? Questo è semplicemente il caso perché il metodo di estensione utilizzato qui utilizza IEnumerable<T> come tipo su cui è definito. Vedi come ToString() su un string. Poiché string è un oggetto, deriva il metodo ToString(), anche se inutile nel caso di un string. Qui, il metodo di estensione causa questa disponibilità "inutile" del metodo.

+2

Non è così inutile. È possibile modificare il tipo effettivo senza rompere il resto del codice. Quindi è possibile sostituire l'array con una query di database o elenco o hashset o altro, ma l''AsEnumerable' funziona sempre e anche il resto del codice dopo. Quindi 'AsEnumerable' è come un contratto. –

+1

Questo non sta rispondendo alla domanda posta, è semplicemente fornendo informazioni tangenzialmente correlate, e come tale, dovrebbe essere solo un commento. – Servy

+0

In effetti, Servy lo ha coperto bene. Volevo solo sottolineare "Perché la matrice ha quel metodo se in realtà non fa nulla?" parte della domanda. In alcuni casi ha uno scopo, ma non tutti. –

4

Hai un paio di buone risposte qui; Ho pensato di aggiungere alcuni punti di supporto.

In primo luogo, FYI, un metodo "non fare nulla" come questo che restituisce sempre il suo argomento è chiamato "identità", per il motivo ovvio che l'output è identico all'input. Le identità sembrano inutili ma in realtà sono utili di tanto in tanto.

In secondo luogo, se si vuole trasformare una matrice in una sequenza di sola lettura che non ha identità referenziale alla matrice, si può fare una proiezione di identità:

var sequence = from item in array select item; 

o equivalentemente:

var sequence = array.Select(item => item); 

Si noti che la proiezione qui è un'identità; Ho detto che erano utili.

Normalmente LINQ ottimizzerebbe una proiezione di identità; se dici

from item in array where whatever select item; 

quindi la proiezione dell'identità alla fine non viene mai generata perché è solo una perdita di tempo. Cioè, questo significa

array.Where(item => whatever) 

non

array.Where(item => whatever).Select(item => item) 

Ma il compilatore non non sopprimere la proiezione identità nel caso in cui il select è l'unica cosa nella query, proprio perché puoi creare una proiezione che non può essere ricondotta all'array originale.

+0

Quindi ottenere veramente un 'IEnumerable' senza che si tratti di un riferimento alla matrice originale è fare' array.Select (x => x) .AsEnumerable() '? –

+1

@AlexanderDerck 'AsEnumerable' non è necessario, la proiezione è sufficiente. – InBetween

Problemi correlati