Яка різниця між ArrayList
і List<>
в C #?
Це лише той List<>
тип, який ArrayList
не має?
List<>
List<object>
Яка різниця між ArrayList
і List<>
в C #?
Це лише той List<>
тип, який ArrayList
не має?
List<>
List<object>
Відповіді:
Так, досить багато. List<T>
- це родовий клас. Він підтримує збереження значень конкретного типу без викиду на або з нього object
(що могло б виникнути накладні бокси / розпакування, коли T
в цьому ArrayList
випадку є значення значення ). ArrayList
просто зберігає object
посилання. Як загальна колекція, List<T>
реалізує загальний IEnumerable<T>
інтерфейс і може легко використовуватися в LINQ (не вимагаючи жодного Cast
або OfType
виклику).
ArrayList
належить до днів, коли C # не мав дженериків. Це застаріло на користь List<T>
. Не слід використовувати ArrayList
в новому коді, який орієнтується на .NET> = 2.0, якщо вам не доведеться взаємодіяти зі старим API, який його використовує.
ArrayList
під час виконання. Статично, однак, він потребує акторського складу ArrayList
.
Використовуючи це, List<T>
ви можете запобігти помилкам кастингу. Це дуже корисно, щоб уникнути помилки лиття під час виконання .
Приклад:
Тут (за допомогою ArrayList
) ви можете скласти цей код, але пізніше ви побачите помилку виконання.
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
}
Якщо ви використовуєте List
, ви уникаєте цих помилок:
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;
}
Довідка: MSDN
Додати до вищезазначених пунктів. Використання ArrayList
в 64-бітної операційній системі займає в 2 рази більше пам'яті, ніж використання в 32-бітної операційній системі. Тим часом загальний список List<T>
використовує набагато менше пам'яті, ніж the ArrayList
.
наприклад, якщо ми використовуємо 19 ArrayList
Мб у 32-бітовому режимі, це займе 39 МБ у 64-бітному. Але якщо у вас є загальний список List<int>
8MB в 32-розрядному, він зайняв би лише 8,1MB в 64-розрядному, що є колосальним 481% різницею порівняно з ArrayList.
Джерело: Загальний список ArrayList для примітивних типів та 64-бітних
Ще одна різниця, яку слід додати, стосується синхронізації потоків.
ArrayList
забезпечує деяку безпеку потоків через властивість Synchronized, яка повертає захисну нитку обгортку навколо колекції. Обгортка працює, блокуючи всю колекцію під час кожного додавання або видалення. Тому кожен потік, який намагається отримати доступ до колекції, повинен дочекатися своєї черги, щоб зняти один замок. Це не масштабується і може призвести до значної погіршення продуктивності для великих колекцій.
List<T>
не забезпечує жодної синхронізації потоку; код користувача повинен забезпечувати всю синхронізацію, коли елементи додаються або видаляються на декількох потоках одночасно.
Більше інформації тут Синхронізація ниток у .Net Framework
ArrayList
якщо цього можна уникнути, але це дурна причина. Зрештою, обгортка абсолютно не є обов'язковою; якщо вам не потрібно блокування або якщо вам потрібен більш детальний контроль, не використовуйте обгортку.
Проста відповідь:
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
Прочитайте офіційний документ Microsoft : https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/
Примітка . Ви повинні знати Generics, перш ніж зрозуміти різницю: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
ArrayList
- це колекція даних різних типів, тоді як List<>
це збір аналогічних типів власних програм.
ArrayList
не є безпечними, тоді List<T>
як безпечними. Просто :).
Ефективність уже згадується в кількох відповідях як диференціюючий фактор, але для вирішення питання « Наскільки повільніше ArrayList
? "Та" Чому це загально повільніше? ", Подивіться нижче.
Щоразу, коли типи значень використовуються як елементи, продуктивність різко падає ArrayList
. Розглянемо випадок простого додавання елементів. Зважаючи на те, що бокс триває - оскільки ArrayList
додавання приймає лише object
параметри - збирач сміття викликає набагато більше роботи, ніж з List<T>
.
На скільки різниця у часі? Принаймні в кілька разів повільніше, ніж при List<T>
. Просто погляньте на те, що відбувається з кодом, який додає значення до 10 міль int до ArrayList
vs List<T>
:
Це різниця у часі виконання 5 разів у стовпці "Середній", виділеному жовтим кольором. Зауважте також різницю в кількості зібраних сміття для кожного, виділених червоним кольором (немає ГК / 1000 пробігів).
Використання профілера для того, щоб побачити, що відбувається, швидко показує, що більшість часу витрачається на створення GC , на відміну від фактичного додавання елементів. Коричневі смуги нижче представляють блокування активності збору сміття:
Я написав детальний аналіз того, що відбувається з вищевказаним ArrayList
сценарієм тут https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/ .
Подібні висновки наведені у «CLR via C #» Джефрі Ріхтера. З розділу 12 (Загальна література):
[…] Коли я компілюю і запускаю збірку релізів (з увімкненими оптимізаціями) цієї програми на своєму комп’ютері, я отримую наступний вихід.
00: 00: 01.6246959 (GCs = 6) Список <Int32>
00: 00: 10.8555008 (GCs = 390) ArrayList of Int32
00: 00: 02.5427847 (GCs = 4) Список <String>
00: 00: 02.7944831 (GCs = 7 ) ArrayList of StringВихідні дані показують, що використання алгоритму загального списку типу Int32 набагато швидше, ніж використання не загального алгоритму ArrayList з Int32. Насправді різниця феноменальна: 1,6 секунди проти майже 11 секунд. Це ~ в 7 разів швидше ! Крім того, використання типу значень (Int32) з ArrayList викликає безліч бокс-операцій, що призводить до 390 збору сміття. Тим часом алгоритм «Список» потребував 6 сміттєзбірників.
Я думаю, відмінності між ArrayList
і List<T>
є:
List<T>
, де T - значення типу швидше, ніж ArrayList
. Це відбувається тому, що ви List<T>
уникаєте боксу / розпакування (де T - значення типу).ArrayList
використовується просто для зворотної сумісності. (це не реальна різниця, але я думаю, що це важливо зауважити).ArrayList
тодіList<T>
ArrayList
має IsSynchronized
майно. Отже, створити та використовувати синхронізовано легко ArrayList
. Я не знайшов IsSynchronized
майно для List<T>
. Також пам’ятайте, що такий тип синхронізації є відносно неефективним, 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
має ArrayList.SyncRoot
властивість, яку можна використовувати для синхронізації ( msdn ). List<T>
не має SyncRoot
властивості, тому в наступній конструкції вам потрібно використовувати якийсь об'єкт, якщо ви використовуєте List<T>
:
ArrayList myCollection = new ArrayList();
lock(myCollection.SyncRoot) // ofcourse you can use another object for this goal
{
foreach (object item in myCollection)
{
// ...
}
}
Як зазначено в документації .NET Framework
Ми не рекомендуємо використовувати
ArrayList
клас для нової розробки. Натомість радимо скористатись загальнимList<T>
класом.ArrayList
Клас призначений для зберігання різнорідних колекцій об'єктів. Однак це не завжди пропонує найкращі показники. Натомість рекомендуємо:
- Для неоднорідної колекції об’єктів використовуйте тип
List<Object>
(у C #) абоList(Of Object)
(у Visual Basic).- Для однорідної колекції предметів використовуйте
List<T>
клас.
Див. Також Колекції, що не є загальними, не слід використовувати
Використовуючи "Список", ви можете запобігти помилкам введення. Це дуже корисно, щоб уникнути помилки лиття під час виконання.
Приклад:
Тут (за допомогою ArrayList) ви можете скласти цей код, але пізніше ви побачите помилку виконання.
// 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.
}
}
Для мене це все про знання ваших даних. Якщо я продовжую розширювати свій код на основі ефективності, мені доведеться вибрати параметр "Список" як спосіб розшифровки моїх даних без зайвого кроку, коли завжди цікавляться типи, особливо "Спеціальні типи". Якщо машина розуміє різницю і може визначитись із тим, з яким типом даних я справді маю справу, то чому я повинен заважати і витрачати час на рух за цирацій визначення "ЯКЩО ІНШЕ"? Моя філософія полягає в тому, щоб дозволити машині працювати для мене, а не мені працювати на машині? Знання унікальних відмінностей різних команд кодового коду проходить довгий шлях у тому, щоб зробити ваш код максимально ефективним.
Том Джонсон (один вхід ... один вихід)