ArrayList vs List <> in C #


412

Qual è la differenza tra ArrayListe List<>in C #?

È solo quello che List<>ha un tipo mentre ArrayListno?


5
possibile duplicato di ArrayList vs List <oggetto>
John Saunders,

5
È una domanda vicina, ma penso che non sia esattamente duplicato. Questo chiede List<>in generale, mentre quello chiede List<object>specificamente
goodeye

Trovato questo blog molto utile, potrebbe aiutare. Ho pensato di condividere il link: fintechexplained.blogspot.co.uk/2017/07/…
InfoLearner

Risposte:


533

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.


Ti dispiacerebbe spiegare perché hai usato "boxe" e non "casting"? Che boxe succede qui? Gli oggetti sono allocati / deallocati?
Benjamin Gruenbaum,

2
@BenjaminGruenbaum Hai ragione sul fatto che il casting sarebbe più generale. Detto questo, la vera differenza in fase di runtime è quando hai a che fare con tipi di valore (che è quello che ho assunto quando ho scritto "boxing"). Per i tipi di riferimento, il comportamento è effettivamente lo stesso del ArrayListruntime. Staticamente però, richiederà un cast con ArrayList.
Mehrdad Afshari,

Mi chiedevo se il framework dovrebbe limitare T al tipo di "oggetto", poiché ArrayList lo consente implicitamente.
rajibdotnet,

Per quanto riguarda la deprecazione delle raccolte non tipizzate, vedere Generics Considered Harmful
Ant_222,

@ Ant_222, quel blog è stato scritto quasi 15 anni fa. Penso che le prove dell'ultimo decennio + abbiano dimostrato che i generici non sono dannosi. :)
Scott Adams,

101

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


È possibile controllare il tipo quando si estrae da ArrayList per evitare errori di trasmissione. Oggi le persone usano l'oggetto, rendendo ArrayList non più necessario.
Cambia il

1
I +1 alla giustificazione, ma puoi ancora fare se (num è int) {} al tuo elenco di array per evitare errori
Mina Gabriel,

Prevenire errori di lancio e spese generali di boxe. Praticamente le ragioni dei generici in generale.
Marsze,

26

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


5
questo vale solo per la memorizzazione di tipi di valore, non di tipi di riferimento. la differenza è dovuta al fatto che un arraylist può contenere solo puntatori e che i dati stessi devono essere archiviati altrove. D'altra parte, i tipi di valore possono essere memorizzati direttamente in un elenco.
Rasmus Damgaard Nielsen,

19

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


Non sto dicendo che dovresti usare 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.
Thorarin,

1
Se vuoi la sicurezza dei thread, ti suggerisco di esaminare lo spazio dei nomi System.Collections.Concurrent prima di prendere in considerazione ArrayList.
Ykok,

15

La risposta semplice è

ArrayList è non generico

  • È un tipo di oggetto, quindi è possibile memorizzare qualsiasi tipo di dati al suo interno.
  • È possibile memorizzare qualsiasi valore (tipo di valore o tipo di riferimento) come stringa, int, impiegato e oggetto in ArrayList. (Nota e)
  • Boxing e Unboxing accadranno.
  • Non digitare sicuro.
  • È più vecchio

L'elenco è generico

  • È un tipo di tipo, quindi è possibile specificare la T in fase di esecuzione.
  • È possibile memorizzare un solo valore di tipo T (stringa o int o impiegato o oggetto) in base alla dichiarazione. (Nota o)
  • Boxing e Unboxing non accadranno.
  • Digitare sicuro.
  • È più recente

Esempio:

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/

inserisci qui la descrizione dell'immagine

Nota : è necessario conoscere Generics prima di comprendere la differenza: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/


4

ArrayListsono le raccolte di dati di tipi diversi mentre List<>è la raccolta di tipi simili di sua proprietà.



2

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>: inserisci qui la descrizione dell'immagine

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: inserisci qui la descrizione dell'immagine

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 String

L'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.


1

Penso che le differenze tra ArrayListe List<T>siano:

  1. List<T>, dove T è di tipo valore è più veloce di ArrayList. Questo perché List<T>evita il boxing / unboxing (dove T è di tipo valore).
  2. Molte fonti dicono - di solito ArrayListusato solo per compatibilità con le versioni precedenti. (non è una vera differenza, ma penso che sia una nota importante).
  3. Riflessione è più facile con non generico ArrayListalloraList<T>
  4. 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 prop
  5. ArrayListha 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)
        {
            // ...
        }
    }

0

Come menzionato nella documentazione di .NET Framework

Non è consigliabile utilizzare la ArrayListclasse per nuovi sviluppi. Invece, ti consigliamo di utilizzare la List<T> classe generica . La ArrayListclasse è 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 #) o List(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

tabella mostra come i tipi di raccolta non generici possono essere sostituiti con le loro controparti generiche


-2

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.
        }
    }

Cosa aggiunge questo oltre alla risposta data tre anni prima? Ha quasi lo stesso testo alla lettera, senza collegamento alla fonte, senza una formattazione corretta, ecc.
Douglas Zare,

-3

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)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.