Qual è la differenza tra ArrayListe List<>in C #?
È solo quello che List<>ha un tipo mentre ArrayListno?
List<>in generale, mentre quello chiede List<object>specificamente
Qual è la differenza tra ArrayListe List<>in C #?
È solo quello che List<>ha un tipo mentre ArrayListno?
List<>in generale, mentre quello chiede List<object>specificamente
Risposte:
Sì, praticamente. List<T>è una classe generica. Supporta la memorizzazione di valori di un tipo specifico senza eseguire il casting da o verso object(il che avrebbe comportato un sovraccarico di box / unboxing quando si Ttratta di un tipo di valore nel ArrayListcaso). ArrayListmemorizza semplicemente objectriferimenti. Come raccolta generica, List<T>implementa l' IEnumerable<T>interfaccia generica e può essere utilizzata facilmente in LINQ (senza richiedere alcuna Casto OfTypechiamata).
ArrayListappartiene ai giorni in cui C # non aveva generici. È deprecato a favore di List<T>. Non è necessario utilizzare ArrayListnel nuovo codice destinato a .NET> = 2.0 a meno che non sia necessario interfacciarsi con una vecchia API che lo utilizza.
ArrayListruntime. Staticamente però, richiederà un cast con ArrayList.
Usando List<T>puoi prevenire errori di casting. È molto utile evitare un errore di casting runtime .
Esempio:
Qui (usando ArrayList) puoi compilare questo codice ma vedrai un errore di esecuzione in seguito.
ArrayList array1 = new ArrayList();
array1.Add(1);
array1.Add("Pony"); //No error at compile process
int total = 0;
foreach (int num in array1)
{
total += num; //-->Runtime Error
}
Se si utilizza List, si evitano questi errori:
List<int> list1 = new List<int>();
list1.Add(1);
//list1.Add("Pony"); //<-- Error at compile process
int total = 0;
foreach (int num in list1 )
{
total += num;
}
Riferimento: MSDN
Da aggiungere ai punti precedenti. L'utilizzo ArrayListnel sistema operativo a 64 bit richiede 2x memoria rispetto all'utilizzo nel sistema operativo a 32 bit. Nel frattempo, l'elenco generico List<T>utilizzerà molta memoria insufficiente rispetto a ArrayList.
per esempio se usiamo un ArrayList19 MB a 32 bit, ci vorranno 39 MB a 64 bit. Ma se hai un elenco genericoList<int> di 8 MB a 32 bit, occorrerebbero solo 8,1 MB a 64 bit, il che è una differenza enorme del 481% rispetto ad ArrayList.
Fonte: ArrayList's vs. Elenco generico per tipi primitivi e 64 bit
Un'altra differenza da aggiungere è rispetto alla sincronizzazione dei thread.
ArrayListfornisce un po 'di sicurezza dei thread tramite la proprietà Synchronized, che restituisce un wrapper thread-safe attorno alla raccolta. Il wrapper funziona bloccando l'intera raccolta su ogni operazione di aggiunta o rimozione. Pertanto, ogni thread che sta tentando di accedere alla raccolta deve attendere il proprio turno per ottenere un blocco. Questo non è scalabile e può causare un significativo peggioramento delle prestazioni per grandi raccolte.
List<T>non fornisce alcuna sincronizzazione dei thread; il codice utente deve fornire tutta la sincronizzazione quando gli elementi vengono aggiunti o rimossi contemporaneamente su più thread.
Maggiori informazioni qui Sincronizzazione di thread in .Net Framework
ArrayListse può essere evitato, ma questa è una ragione sciocca. Il wrapper è del tutto facoltativo dopo tutto; se non è necessario il blocco o se è necessario un controllo più granulare, non utilizzare il wrapper.
La risposta semplice è
ArrayList arrayList = new ArrayList();
List<int> list = new List<int>();
arrayList.Add(1);
arrayList.Add("String");
arrayList.Add(new object());
list.Add(1);
list.Add("String"); // Compile-time Error
list.Add(new object()); // Compile-time Error
Si prega di leggere il documento ufficiale di Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/
Nota : è necessario conoscere Generics prima di comprendere la differenza: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
ArrayListsono le raccolte di dati di tipi diversi mentre List<>è la raccolta di tipi simili di sua proprietà.
ArrayListnon sono sicuri, mentre List<T>sono sicuri. Semplice :).
Le prestazioni sono già state menzionate in diverse risposte come un fattore di differenziazione, ma per affrontare il " Quanto è più lento ArrayList? "E" Perché è più lento nel complesso? ", Dai un'occhiata qui sotto.
Ogni volta che i tipi di valore vengono utilizzati come elementi, le prestazioni diminuiscono drasticamente con ArrayList. Considera il caso di aggiungere semplicemente elementi. A causa della boxe in corso - poiché ArrayListAggiungi richiede solo objectparametri - Garbage Collector viene attivato per eseguire molto più lavoro rispetto a List<T>.
Quanto è la differenza di tempo? Almeno diverse volte più lentamente che con List<T>. Dai un'occhiata a cosa succede con il codice che aggiunge 10 milioni di valori int a un ArrayListvs List<T>:

Questa è una differenza di tempo di esecuzione di 5x nella colonna "Media", evidenziata in giallo. Notare anche la differenza nel numero di raccolte di rifiuti eseguite per ciascuna, evidenziate in rosso (nessun numero di GC / 1000 esecuzioni).
L'uso di un profiler per vedere cosa sta succedendo mostra rapidamente che la maggior parte del tempo viene impiegato per fare GC , invece di aggiungere effettivamente elementi. Le barre marroni in basso rappresentano il blocco dell'attività di Garbage Collector:

Ho scritto un'analisi dettagliata di ciò che accade con lo ArrayListscenario sopra qui https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ .
Risultati simili si trovano in "CLR via C #" di Jeffrey Richter. Dal capitolo 12 (Generics):
[…] Quando compilo ed eseguo una build di rilascio (con le ottimizzazioni attivate) di questo programma sul mio computer, ottengo il seguente output.
00: 00: 01.6246959 (GCs = 6) Elenco <Int32>
00: 00: 10.8555008 (GCs = 390) ArrayList of Int32
00: 00: 02.5427847 (GCs = 4) Elenco <String>
00: 00: 02.7944831 (GCs = 7 ) ArrayList of StringL'output qui mostra che l'utilizzo dell'algoritmo List generico con il tipo Int32 è molto più veloce rispetto all'uso dell'algoritmo ArrayList non generico con Int32. In effetti, la differenza è fenomenale: 1,6 secondi contro quasi 11 secondi. Questo è ~ 7 volte più veloce ! Inoltre, l'utilizzo di un tipo di valore (Int32) con ArrayList provoca molte operazioni di inscatolamento, con conseguente 390 garbage collection. Nel frattempo, l'algoritmo List richiedeva 6 garbage collection.
Penso che le differenze tra ArrayListe List<T>siano:
List<T>, dove T è di tipo valore è più veloce di ArrayList. Questo perché List<T>evita il boxing / unboxing (dove T è di tipo valore).ArrayListusato solo per compatibilità con le versioni precedenti. (non è una vera differenza, ma penso che sia una nota importante).ArrayListalloraList<T>ArrayListha IsSynchronizedproprietà. Quindi, è facile da creare e utilizzare sincronizzato ArrayList. Non ho trovato IsSynchronizedproprietà per List<T>. Inoltre, tieni presente che questo tipo di sincronizzazione è relativamente inefficiente, msdn ):
var arraylist = new ArrayList();
var arrayListSyncronized = ArrayList.Synchronized(arraylist
Console.WriteLine($"syncronized {arraylist.IsSynchronized}");
Console.WriteLine($"syncronized {arrayListSyncronized.IsSynchronized}");
var list = new List<object>();
var listSyncronized = ArrayList.Synchronized(list);
Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such prop
Console.WriteLine($"syncronized {list.IsSynchronized}");//error, no such propArrayListha ArrayList.SyncRootproprietà che possono essere utilizzate per la sincronizzazione ( msdn ). List<T>non ha SyncRootproprietà, quindi nella seguente costruzione è necessario utilizzare alcuni oggetti se si utilizza List<T>:
ArrayList myCollection = new ArrayList();
lock(myCollection.SyncRoot) // ofcourse you can use another object for this goal
{
foreach (object item in myCollection)
{
// ...
}
}Come menzionato nella documentazione di .NET Framework
Non è consigliabile utilizzare la
ArrayListclasse per nuovi sviluppi. Invece, ti consigliamo di utilizzare laList<T>classe generica . LaArrayListclasse è progettata per contenere raccolte eterogenee di oggetti. Tuttavia, non offre sempre le migliori prestazioni. Raccomandiamo invece quanto segue:
- Per una raccolta eterogenea di oggetti, utilizzare il tipo
List<Object>(in C #) oList(Of Object)(in Visual Basic).- Per una raccolta omogenea di oggetti, utilizzare la
List<T>classe.
Vedi anche Le raccolte non generiche non devono essere utilizzate
Usando "Elenco" è possibile prevenire errori di trasmissione. È molto utile evitare un errore di casting runtime.
Esempio:
Qui (usando ArrayList) puoi compilare questo codice ma vedrai un errore di esecuzione in seguito.
// Create a new ArrayList
System.Collections.ArrayList mixedList = new System.Collections.ArrayList();
// Add some numbers to the list
mixedList.Add(7);
mixedList.Add(21);
// Add some strings to the list
mixedList.Add("Hello");
mixedList.Add("This is going to be a problem");
System.Collections.ArrayList intList = new System.Collections.ArrayList();
System.Collections.ArrayList strList = new System.Collections.ArrayList();
foreach (object obj in mixedList)
{
if (obj.GetType().Equals(typeof(int)))
{
intList.Add(obj);
}
else if (obj.GetType().Equals(typeof(string)))
{
strList.Add(obj);
}
else
{
// error.
}
}
Per me è tutto sulla conoscenza dei tuoi dati. Se continuo ad espandere il mio codice sulla base dell'efficienza, dovrei scegliere l'opzione Elenco come modo per decifrare i miei dati senza il passaggio inutile di chiedermi sempre i tipi, in particolare i "Tipi personalizzati". Se la macchina capisce la differenza e può determinare su quale tipo di dati sto effettivamente trattando, allora perché dovrei intralciarmi e perdere tempo a passare attraverso le determinazioni di "IF THEN ELSE"? La mia filosofia è quella di lasciare che la macchina funzioni per me invece che lavorare sulla macchina? Conoscere le differenze uniche tra i diversi comandi del codice oggetto aiuta a rendere il codice efficiente.
Tom Johnson (Una voce ... Una uscita)