ArrayList vs List <> en C #

412

Cuál es la diferencia entre ArrayList y List<>en C #?

¿Es solo que List<>tiene un tipo mientras ArrayListque no lo tiene?

scatman
fuente
55
posible duplicado de ArrayList vs List <object>
John Saunders el
55
Es una pregunta cercana, pero creo que no exactamente duplicada. Esto pregunta List<>en general, mientras que ese pregunta List<object>específicamente
goodeye
Encontré este blog muy útil, podría ayudar. Pensé que debería compartir el enlace: fintechexplained.blogspot.co.uk/2017/07/…
InfoLearner

Respuestas:

533

Si, mas o menos. List<T>Es una clase genérica. Es compatible con el almacenamiento de valores de un tipo específico sin conversión hacia o desde object(que habría incurrido en gastos generales de boxeo / unboxing cuando Tes un tipo de valor en el ArrayListcaso). ArrayListsimplemente almacena objectreferencias. Como una colección genérica, List<T>implementa la IEnumerable<T>interfaz genérica y se puede usar fácilmente en LINQ (sin requerir ninguna CastoOfType llamar).

ArrayListpertenece a los días en que C # no tenía genéricos. Está en desuso a favor de List<T>. No debe usar un ArrayListcódigo nuevo que apunte a .NET> = 2.0 a menos que tenga que interactuar con una API antigua que lo usa.

Mehrdad Afshari
fuente
¿Te importaría explicar por qué usaste "boxeo" y no "casting"? ¿Qué boxeo pasa aquí? ¿Los objetos están asignados / desasigados?
Benjamin Gruenbaum
2
@BenjaminGruenbaum Tienes razón en que el casting sería más general. Dicho esto, la verdadera diferencia en tiempo de ejecución es cuando se trata de tipos de valores (que es lo que asumí cuando escribí "boxeo"). Para los tipos de referencia, el comportamiento es efectivamente el mismo que ArrayListen tiempo de ejecución. Aunque estáticamente, requerirá un yeso con ArrayList.
Mehrdad Afshari
Me preguntaba si el framework debería restringir que T sea del tipo "objeto", ya que ArrayList lo permite implícitamente.
rajibdotnet
Con respecto a la depreciación de colecciones sin tipo, vea Genéricos considerados perjudiciales
Ant_222
@ Ant_222, ese blog fue escrito hace casi 15 años. Creo que la evidencia de la última década ha demostrado que los genéricos no son dañinos. :)
Scott Adams
101

Usarlo List<T>puede evitar errores de transmisión. Es muy útil para evitar un error de transmisión en tiempo de ejecución .

Ejemplo:

Aquí (usando ArrayList) puede compilar este código, pero verá un error de ejecución más adelante.

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
}

Si lo usa List, evita estos errores:

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

Referencia: MSDN

termas
fuente
Puede verificar el tipo cuando extrae de ArrayList para evitar errores de conversión. Hoy en día las personas usan objetos, haciendo que ArrayList ya no sea necesario.
Cambiar el
1
i +1 a la justificación, pero aún puede hacerlo si (num es int) {} a su lista de matriz para evitar errores
Mina Gabriel
Prevenir errores de fundición y gastos generales de boxeo. Más o menos las razones de los genéricos en general.
marsze
26

Para agregar a los puntos anteriores. El uso ArrayListen el sistema operativo de 64 bits requiere 2 veces más memoria que el uso en el sistema operativo de 32 bits. Mientras tanto, la lista genérica List<T>usará mucha poca memoria que laArrayList .

por ejemplo, si utilizamos una ArrayListde 19 MB en 32 bits, se necesitarían 39 MB en 64 bits. Pero si tienes una lista genéricaList<int> de 8 MB en 32 bits, solo necesitaría 8.1 MB en 64 bits, lo que es una gran diferencia del 481% en comparación con ArrayList.

Fuente: ArrayList's vs. Lista genérica para tipos primitivos y 64 bits

Anoop
fuente
55
eso solo es cierto para almacenar tipos de valor, no tipos de referencia. La diferencia se debe al hecho de que una lista de arrays solo puede contener punteros, y los datos en sí mismos deben almacenarse en otro lugar. Por otro lado, los tipos de valores se pueden almacenar directamente en una lista.
Rasmus Damgaard Nielsen
19

Otra diferencia para agregar es con respecto a la sincronización de subprocesos.

ArrayListproporciona cierta seguridad de subprocesos a través de la propiedad Sincronizada, que devuelve un contenedor seguro para subprocesos alrededor de la colección. El contenedor funciona bloqueando toda la colección en cada operación de agregar o quitar. Por lo tanto, cada subproceso que intenta acceder a la colección debe esperar su turno para tomar el único bloqueo. Esto no es escalable y puede causar una degradación significativa del rendimiento para grandes colecciones.

List<T>no proporciona ninguna sincronización de subprocesos; el código de usuario debe proporcionar toda la sincronización cuando los elementos se agregan o eliminan en varios subprocesos simultáneamente.

Más información aquí Sincronización de subprocesos en .Net Framework

Referencia nula
fuente
No digo que debas usarlo ArrayListsi se puede evitar, pero esta es una razón tonta. El contenedor es completamente opcional después de todo; Si no necesita bloqueo o si necesita un control más granular, no use el envoltorio.
Thorarin
1
Si desea seguridad de subprocesos, le sugiero que consulte el espacio de nombres System.Collections.Concurrent antes de considerar ArrayList.
Ykok
15

La respuesta simple es,

ArrayList es no genérico

  • Es un tipo de objeto, por lo que puede almacenar cualquier tipo de datos en él.
  • Puede almacenar cualquier valor (tipo de valor o tipo de referencia) como string, int, employee y object en ArrayList. (Nota y)
  • Boxing y Unboxing sucederán.
  • No es seguro.
  • Es mayor

La lista es genérica

  • Es un tipo de tipo, por lo que puede especificar la T en tiempo de ejecución.
  • Puede almacenar un único valor de Tipo T (cadena o int o empleado u objeto) según la declaración. (Nota o)
  • Boxeo y Unboxing no sucederán.
  • Escriba seguro.
  • Es mas nuevo.

Ejemplo:

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

Lea el documento oficial de Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/

ingrese la descripción de la imagen aquí

Nota : debe conocer los genéricos antes de comprender la diferencia: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/

Aravin
fuente
4

ArrayListes la recopilación de datos de diferentes tipos, mientras que List<>es la recopilación de un tipo similar de sus propias dependencias.

Ley Kant Dayal
fuente
3

ArrayListno son de tipo seguro, mientras que List<T>son de tipo seguro. Simple :).

Hassan Rahman
fuente
2

El rendimiento ya se ha mencionado en varias respuestas como un factor diferenciador, pero para abordar el tema " ¿Cuánto más lento es el ArrayList? "Y" ¿Por qué es más lento en general?", Eche un vistazo a continuación.

Siempre que los tipos de valor se utilizan como elementos, el rendimiento disminuye drásticamente con ArrayList. Considere el caso de simplemente agregar elementos. Debido a que el boxeo continúa, ya que ArrayListAdd solo toma objectparámetros, el recolector de basura se activa para realizar mucho más trabajo que con List<T>.

¿Cuánto es la diferencia horaria? Al menos varias veces más lento que con List<T>. Solo eche un vistazo a lo que sucede con el código que agrega valores de 10 mil int a un ArrayListvs List<T>: ingrese la descripción de la imagen aquí

Esa es una diferencia de tiempo de ejecución de 5x en la columna 'Media', resaltada en amarillo. Tenga en cuenta también la diferencia en el número de recolecciones de basura realizadas para cada uno, resaltado en rojo (no de GC / 1000 ejecuciones).

El uso de un generador de perfiles para ver lo que sucede rápidamente muestra que la mayor parte del tiempo se gasta haciendo GC , en lugar de agregar elementos. Las barras marrones a continuación representan el bloqueo de la actividad del recolector de basura: ingrese la descripción de la imagen aquí

He escrito un análisis detallado de lo que sucede con el ArrayListescenario anterior aquí https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ .

Hallazgos similares se encuentran en "CLR vía C #" de Jeffrey Richter. Del capítulo 12 (Genéricos):

[…] Cuando compilo y ejecuto una versión de lanzamiento (con las optimizaciones activadas) de este programa en mi computadora, obtengo el siguiente resultado.

00: 00: 01.6246959 (GCs = 6) Lista <Int32>
00: 00: 10.8555008 (GCs = 390) ArrayList de Int32
00: 00: 02.5427847 (GCs = 4) Lista <String>
00: 00: 02.7944831 (GCs = 7 ) ArrayList of String

El resultado aquí muestra que usar el algoritmo genérico List con el tipo Int32 es mucho más rápido que usar el algoritmo ArrayList no genérico con Int32. De hecho, la diferencia es fenomenal: 1.6 segundos versus casi 11 segundos. ¡Eso es ~ 7 veces más rápido ! Además, el uso de un tipo de valor (Int32) con ArrayList hace que se produzcan muchas operaciones de boxeo, lo que resulta en 390 recolecciones de basura. Mientras tanto, el algoritmo List requirió 6 recolecciones de basura.

Mihai Albert
fuente
1

Creo que las diferencias entre ArrayListy List<T>son:

  1. List<T>, donde T es de tipo valor es más rápido que ArrayList. Esto se debe a que List<T>evita el boxing / unboxing (donde T es de tipo valor).
  2. Muchas fuentes dicen que generalmente se ArrayListusa solo para compatibilidad con versiones anteriores. (No es una diferencia real, pero creo que es una nota importante).
  3. La reflexión es más fácil con no genérico ArrayListcontinuación,List<T>
  4. ArrayListTiene IsSynchronizedpropiedad. Por lo tanto, es fácil de crear y usar sincronizado ArrayList. No encontré IsSynchronizedpropiedad para List<T>. También tenga en cuenta que este tipo de sincronización es relativamente ineficiente, 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. ArrayListtiene una ArrayList.SyncRootpropiedad que se puede usar para la sincronización ( msdn ). List<T>no tiene SyncRootpropiedad, por lo que en la siguiente construcción debe usar algún objeto si usa List<T>:

    ArrayList myCollection = new ArrayList();
    lock(myCollection.SyncRoot) //  ofcourse you can use another object for this goal
    {
        foreach (object item in myCollection)
        {
            // ...
        }
    }
burzhuy
fuente
0

Como se menciona en la documentación de .NET Framework

No recomendamos que use la ArrayListclase para un nuevo desarrollo. En su lugar, le recomendamos que use la List<T> clase genérica . La ArrayListclase está diseñada para contener colecciones heterogéneas de objetos. Sin embargo, no siempre ofrece el mejor rendimiento. En cambio, recomendamos lo siguiente:

  • Para una colección heterogénea de objetos, use el tipo List<Object>(en C #) o List(Of Object)(en Visual Basic).
  • Para una colección homogénea de objetos, use la List<T>clase

Consulte también No se deben usar colecciones no genéricas

la tabla muestra cómo los tipos de colecciones no genéricas pueden reemplazarse por sus equivalentes genéricos

ElasticCode
fuente
-2

Usando "Lista" puede evitar errores de transmisión. Es muy útil para evitar un error de transmisión en tiempo de ejecución.

Ejemplo:

Aquí (usando ArrayList) puede compilar este código pero verá un error de ejecución más adelante.

    // 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.
        }
    }
Deepak
fuente
¿Qué agrega esto más allá de la respuesta que las termas dieron tres años antes? Tiene casi el mismo texto textualmente, sin vincular a la fuente, sin formatear correctamente, etc.
Douglas Zare
-3

Para mí, todo se trata de conocer sus datos. Si continúo expandiendo mi código sobre la base de la eficiencia, tendría que elegir la opción Lista como una forma de descifrar mis datos sin el paso innecesario de siempre preguntarme acerca de los tipos, especialmente 'Tipos personalizados'. Si la máquina entiende la diferencia y puede determinar en qué tipo de datos estoy tratando realmente, ¿por qué debería interponerme y perder el tiempo pasando por los giros de las determinaciones 'SI ENTONCES?' ¿Mi filosofía es dejar que la máquina funcione para mí en lugar de que yo trabaje en la máquina? Conocer las diferencias únicas de los diferentes comandos de código de objeto ayuda mucho a que su código sea tan eficiente.

Tom Johnson (una entrada ... una salida)

usuario1998271
fuente