Qual è la differenza tra IEnumerablee Array?
Qual è la differenza tra IListe List?
Questi sembrano avere la stessa funzione.
Qual è la differenza tra IEnumerablee Array?
Qual è la differenza tra IListe List?
Questi sembrano avere la stessa funzione.
Risposte:
IEnumerable fornisce solo funzionalità "iterabili" minime. Puoi attraversare la sequenza, ma questo è tutto. Questo ha degli svantaggi - per esempio, è molto inefficiente contare gli elementi usando IEnumerable, o per ottenere l'ennesimo elemento - ma ha anche dei vantaggi - per esempio, un IEnumerable potrebbe essere una sequenza infinita, come la sequenza dei numeri primi.
Array è una raccolta di dimensioni fisse con accesso casuale (ovvero è possibile indicizzarla).
List è una raccolta di dimensioni variabili (ovvero è possibile aggiungere e rimuovere elementi) con accesso casuale.
IList è un'interfaccia che astrae le funzionalità di elenco (conteggio, aggiunta, rimozione, accesso all'indicizzatore) dalle varie classi concrete come List, BindingList, ObservableCollection, ecc.
IEnumerable è un'interfaccia che consente l'iterazione attraverso una raccolta di elementi (ad esempio tramite la parola chiave foreach).
Un array è un intrinseco .NET. Contiene oggetti dello stesso tipo, ma di dimensioni fisse. Una volta creato un array con x elementi, non può crescere o ridursi.
IList definisce l'interfaccia per un elenco e implementa anche IEnumerable.
List implementa l'interfaccia IList; è un tipo concreto di lista.
La differenza tra gli elenchi .NET e gli array è che agli elenchi possono essere aggiunti elementi: crescono abbastanza da contenere tutti gli elementi richiesti. L'elenco lo memorizza internamente in un array e, quando l'array non è più abbastanza grande da contenere tutti gli elementi, viene creato un nuovo array e gli elementi vengono copiati.
IList e gli array implementano entrambi IEnumerable. È così che funzionano le interfacce: le classi implementano il contratto e si comportano in modo simile e di conseguenza possono essere trattate in modo simile (sai che la classe implementa IEnumerable, non è necessario conoscere il come o il perché). Ti suggerisco di leggere su interfacce e così via.
IEnumerable e IList sono interfacce . Array e List sono classi. Array implementa IEnumerable. List implementa IList che estende IEnumerable.
Modifica: come itowlson ha menzionato in un commento, Array implementa anche IList.
La generazione di una raccolta IEnumerable è lenta. Esempio:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
Nel metodo Something la chiamata a GetTwoInts () non comporterà effettivamente l'esecuzione del metodo GetTwoInts poiché l'enumerazione non viene mai ripetuta.
twoIntsuna foreachchiamata o twoInts.ToList().
IEnumerableè un'interfaccia general-purpose che viene utilizzato da molte classi, come ad esempio Array, Liste Stringal fine di lasciare che qualcuno iterare su una collezione. Fondamentalmente, è ciò che guida l' foreachaffermazione.
IListè in genere il modo in cui esponi le variabili di tipo Listagli utenti finali. Questa interfaccia consente l'accesso casuale alla raccolta sottostante.
Per completare le altre risposte, nota che c'è una differenza di prestazioni tra IList<T>e List<T>quando si esegue un'istruzione foreach.
Questo perché l'oggetto iteratore restituito da List<T>.GetEnumeratorè un tipo di valore mentre quello restituito da IList<T>.GetEnumeratorè un tipo di riferimento e quindi richiede un'allocazione di memoria (vedere Enumeratore del tipo di valore di elenco in c # ).
A mio parere, IList<T>non è comunque una buona interfaccia. Ad esempio, la chiamata Addpuò generare (vedere Perché array implementa IList? ). Se hai bisogno di incapsulamento, faresti meglio a usare IEnumerable<T>o IReadOnlyList<T>.
Oltre ad altre risposte, la comprensione della differenza tra Enumerable e List / Array quando si usa LINQ può avere un enorme impatto sulle prestazioni. In breve, Enumerable può essere percepito come un generatore di query mentre List / Array è il risultato della query.
Nel contesto di LINQ to SQL che utilizza EntityFramework, il primo si limita a creare la query SQL senza eseguirla sul database né caricare dati in memoria, mentre il secondo è l'opposto. Ecco perché rinviamo la chiamata .ToList()fino a quando non ne abbiamo bisogno nella memoria per eseguire la logica di business.
In un altro contesto, l'espressione LINQ che restituisce IEnumerable rinvia l'esecuzione fino a quando non .ToList()viene chiamata. Considera l'esempio di seguito:
void Main()
{
var w1 = "AB".AsEnumerable();
Console.WriteLine($"W1: 1");
w1 = w1.Where(W1);
Console.WriteLine($"W1: 2");
w1 = w1.Where(W2);
Console.WriteLine($"W1: 3");
w1.ToList();
Console.WriteLine($"----------");
var w2 = "CD".AsEnumerable();
Console.WriteLine($"W2: 1");
w2 = w2.Where(W1);
Console.WriteLine($"W2: 2");
w2 = w2.ToList();
Console.WriteLine($"W2: 3");
w2 = w2.Where(W2);
Console.WriteLine($"W2: 4");
w2.ToList();
Console.WriteLine($"----------");
}
bool W1(char arg)
{
Console.WriteLine($"W1:{arg}");
return true;
}
bool W2(char arg)
{
Console.WriteLine($"W2:{arg}");
return true;
}
OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------
Nel primo esempio, due .Where()vengono "aggiunti" ed eseguiti insieme alla fine quando .ToList()viene chiamato con l'elemento " A " che passa prima attraverso la pipe e poi l'elemento " B ", quindi vedendo " AABB " nell'output, mentre nel secondo esempio, la .Where()viene eseguito ogni volta che se chiamiamo .ToList()subito dopo, quindi, vedere " CD " e poi " CD " ancora una volta, l'uscita per due volte. Pertanto, ogni volta che un oggetto Enumerable viene convertito in un elenco o in un array, costerà un'iterazione O (n) su tutti gli elementi della raccolta, il che avrà un impatto sulle prestazioni quando la raccolta è grande.
Sebbene non tendiamo a scrivere codice in questo modo chiamando .ToList()tra le chiamate LINQ, ciò accadrebbe più frequentemente quando fattorizziamo il codice in metodi riutilizzabili che restituiscono List/Arraypiuttosto che IEnumerable.
Questo tuttavia non significa che dovremmo sempre operare IEnumerable. Come accennato da towlson , operazioni come .Count()causeranno l'iterazione sulla raccolta mentre un elenco o un array avrebbe queste informazioni precalcolate e quindi la conversione in List/Arraysarebbe più efficiente se si prevede di chiamare .Count()più volte. Questo è anche il motivo per cui c'è una .Countproprietà in una lista piuttosto che un .Count()metodo per contarla.
Questo è un vecchio post, ma ho ancora pensato di rispondere. IEnumerable è un comportamento mentre Array è una struttura dati (raccolta contigua di elementi con dimensioni fisse, che facilita l'accesso agli elementi tramite indici). Quando un Array implementa IEnumerable, si suppone che rappresenti anche la proprietà intrinseca di IEnumerable (per facilitare l'iterazione sulla raccolta).