Quelle est la différence entre ArrayList
et List<>
en C #?
Est-ce seulement celui qui List<>
a un type alors ArrayList
que non?
List<>
en général, alors que l'on pose des questions sur List<object>
spécifiquement
Quelle est la différence entre ArrayList
et List<>
en C #?
Est-ce seulement celui qui List<>
a un type alors ArrayList
que non?
List<>
en général, alors que l'on pose des questions sur List<object>
spécifiquement
Réponses:
Oui, à peu près. List<T>
est une classe générique. Il prend en charge le stockage de valeurs d'un type spécifique sans transtypage vers ou à partir de object
(ce qui aurait entraîné des frais généraux de boxe / unboxing alors qu'il T
s'agit d'un type de valeur dans le ArrayList
cas). ArrayList
stocke simplement les object
références. En tant que collection générique, List<T>
implémente l' IEnumerable<T>
interface générique et peut être utilisée facilement dans LINQ (sans nécessiter Cast
ni OfType
appel).
ArrayList
appartient à l'époque où C # n'avait pas de génériques. Il est déconseillé en faveur de List<T>
. Vous ne devez pas utiliser ArrayList
dans un nouveau code qui cible .NET> = 2.0, sauf si vous devez vous interfacer avec une ancienne API qui l'utilise.
ArrayList
exécution. Mais statiquement, il faudra un casting avec ArrayList
.
L' utilisation , List<T>
vous pouvez éviter les erreurs de coulée. Il est très utile d'éviter une erreur de transtypage d' exécution .
Exemple:
Ici (en utilisant ArrayList
), vous pouvez compiler ce code mais vous verrez une erreur d'exécution plus tard.
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 vous utilisez List
, vous évitez ces erreurs:
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;
}
Référence: MSDN
Pour ajouter aux points ci-dessus. L'utilisation ArrayList
dans le système d'exploitation 64 bits prend 2 fois plus de mémoire que l'utilisation dans le système d'exploitation 32 bits. Pendant ce temps, la liste générique List<T>
utilise beaucoup moins de mémoire que le ArrayList
.
par exemple, si nous utilisons un ArrayList
de 19 Mo en 32 bits, il faudrait 39 Mo en 64 bits. Mais si vous avez une liste générique List<int>
de 8 Mo en 32 bits, cela ne prendrait que 8,1 Mo en 64 bits, ce qui représente une différence de 481% par rapport à ArrayList.
La source: ArrayList's vs Liste générique pour les types primitifs et 64 bits
Une autre différence à ajouter concerne la synchronisation des threads.
ArrayList
fournit une certaine sécurité des threads via la propriété Synchronized, qui renvoie un wrapper thread-safe autour de la collection. L'encapsuleur fonctionne en verrouillant la collection entière à chaque opération d'ajout ou de suppression. Par conséquent, chaque thread qui tente d'accéder à la collection doit attendre son tour pour prendre le verrou. Ce n'est pas évolutif et peut entraîner une dégradation significative des performances pour les grandes collections.
List<T>
ne fournit aucune synchronisation de thread; le code utilisateur doit fournir toute la synchronisation lorsque des éléments sont ajoutés ou supprimés simultanément sur plusieurs threads.
Plus d'informations ici Synchronisation des threads dans le .Net Framework
ArrayList
si cela peut être évité, mais c'est une raison stupide. L'emballage est entièrement facultatif après tout; si vous n'avez pas besoin de verrouillage ou si vous avez besoin d'un contrôle plus précis, n'utilisez pas le wrapper.
La réponse simple est,
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
Veuillez lire le document officiel de Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/
Remarque : Vous devez connaître les génériques avant de comprendre la différence: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
ArrayList
est la collection de données de types différents, tandis que List<>
la collection de types similaires de ses propres dépendances.
ArrayList
ne sont pas de type sécurisé tandis que List<T>
sont de type sécurisé. Facile :).
La performance a déjà été mentionnée dans plusieurs réponses comme facteur de différenciation, mais pour répondre à la question « Combien est plus lent ArrayList
? »Et« Pourquoi est-il globalement plus lent?», Regardez ci-dessous.
Chaque fois que des types de valeurs sont utilisés en tant qu'éléments, les performances diminuent considérablement avec ArrayList
. Prenons le cas de l'ajout simple d'éléments. En raison de la boxe en cours - comme ArrayList
Add ne prend que des object
paramètres - le Garbage Collector est déclenché pour effectuer beaucoup plus de travail qu'avec List<T>
.
Quelle est la différence de temps? Au moins plusieurs fois plus lentement qu'avec List<T>
. Jetez un coup d'œil à ce qui se passe avec le code ajoutant des valeurs int de 10 mil à un ArrayList
vs List<T>
:
C'est une différence de temps d'exécution de 5x dans la colonne `` Moyenne '', surlignée en jaune. Notez également la différence dans le nombre de récupérations effectuées pour chacune, surlignée en rouge (pas de GC / 1000 exécutions).
L'utilisation d'un profileur pour voir ce qui se passe rapidement montre que la plupart du temps est consacré à des GC , au lieu d'ajouter réellement des éléments. Les barres brunes ci-dessous représentent le blocage de l'activité de Garbage Collector:
J'ai écrit une analyse détaillée de ce qui se passe avec le ArrayList
scénario ci-dessus ici https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ .
Des résultats similaires se trouvent dans «CLR via C #» de Jeffrey Richter. Du chapitre 12 (Génériques):
[…] Lorsque je compile et exécute une version de build (avec les optimisations activées) de ce programme sur mon ordinateur, j'obtiens la sortie suivante.
00: 00: 01.6246959 (GCs = 6) Liste <Int32>
00: 00: 10.8555008 (GCs = 390) ArrayList of Int32
00: 00: 02.5427847 (GCs = 4) List <String>
00: 00: 02.7944831 (GCs = 7 ) ArrayList of StringLa sortie ici montre que l'utilisation de l'algorithme de liste générique avec le type Int32 est beaucoup plus rapide que l'utilisation de l'algorithme ArrayList non générique avec Int32. En fait, la différence est phénoménale: 1,6 seconde contre près de 11 secondes. C'est ~ 7 fois plus rapide ! En outre, l'utilisation d'un type de valeur (Int32) avec ArrayList provoque de nombreuses opérations de boxe, ce qui entraîne 390 récupérations de place. Pendant ce temps, l'algorithme List nécessitait 6 garbage collections.
Je pense que les différences entre ArrayList
et List<T>
sont:
List<T>
, où T est le type valeur est plus rapide que ArrayList
. En effet, List<T>
évite la boxe / unboxing (où T est de type valeur).ArrayList
utilisé uniquement pour des raisons de compatibilité descendante. (ce n'est pas une vraie différence, mais je pense que c'est une note importante).ArrayList
puisList<T>
ArrayList
a une IsSynchronized
propriété. Ainsi, il est facile de créer et d'utiliser synchronisé ArrayList
. Je n'ai pas trouvé de IsSynchronized
propriété pour List<T>
. Gardez également à l'esprit que ce type de synchronisation est relativement inefficace, 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
ArrayList
possède une ArrayList.SyncRoot
propriété qui peut être utilisée pour la synchronisation ( msdn ). List<T>
n'a pas de SyncRoot
propriété, donc dans la construction suivante, vous devez utiliser un objet si vous utilisez List<T>
:
ArrayList myCollection = new ArrayList();
lock(myCollection.SyncRoot) // ofcourse you can use another object for this goal
{
foreach (object item in myCollection)
{
// ...
}
}
Comme mentionné dans la documentation de .NET Framework
Nous vous déconseillons d'utiliser la
ArrayList
classe pour de nouveaux développements. Au lieu de cela, nous vous recommandons d'utiliser laList<T>
classe générique . LaArrayList
classe est conçue pour contenir des collections hétérogènes d'objets. Cependant, il n'offre pas toujours les meilleures performances. Au lieu de cela, nous recommandons ce qui suit:
- Pour une collection hétérogène d'objets, utilisez le type
List<Object>
(en C #) ouList(Of Object)
(en Visual Basic).- Pour une collection homogène d'objets, utilisez la
List<T>
classe.
Voir aussi Les collections non génériques ne doivent pas être utilisées
En utilisant "Liste", vous pouvez éviter les erreurs de casting. Il est très utile d'éviter une erreur de transtypage d'exécution.
Exemple:
Ici (en utilisant ArrayList), vous pouvez compiler ce code mais vous verrez une erreur d'exécution plus tard.
// 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.
}
}
Pour moi, il s'agit de connaître vos données. Si je continue à étendre mon code sur la base de l'efficacité, je devrais choisir l'option Liste comme moyen de déchiffrer mes données sans l'étape inutile de toujours me poser des questions sur les types, en particulier les `` types personnalisés ''. Si la machine comprend la différence et peut déterminer sur quel type de données je traite réellement, alors pourquoi devrais-je gêner et perdre du temps à traverser les girations des déterminations `` IF THEN ELSE ''? Ma philosophie est de laisser la machine fonctionner pour moi au lieu de travailler sur la machine? Connaître les différences uniques des différentes commandes de code objet contribue grandement à rendre votre code aussi efficace.
Tom Johnson (une entrée ... une sortie)