ArrayList vs List <> в C #


412

Яка різниця між ArrayListі List<>в C #?

Це лише той List<>тип, який ArrayListне має?


5
можливий дублікат ArrayList vs List <object>
Джон Саундерс

5
Це близьке питання, але я думаю, що не зовсім повторюваний. Про це List<>List<object>
йдеться

Знайшов цей дуже корисний блог, він може допомогти. Думав, що я повинен поділитися посиланням: fintechexplained.blogspot.co.uk/2017/07/…
InfoLearner

Відповіді:


533

Так, досить багато. List<T>- це родовий клас. Він підтримує збереження значень конкретного типу без викиду на або з нього object(що могло б виникнути накладні бокси / розпакування, коли Tв цьому ArrayListвипадку є значення значення ). ArrayListпросто зберігає objectпосилання. Як загальна колекція, List<T>реалізує загальний IEnumerable<T>інтерфейс і може легко використовуватися в LINQ (не вимагаючи жодного Castабо OfTypeвиклику).

ArrayListналежить до днів, коли C # не мав дженериків. Це застаріло на користь List<T>. Не слід використовувати ArrayListв новому коді, який орієнтується на .NET> = 2.0, якщо вам не доведеться взаємодіяти зі старим API, який його використовує.


Ви б не могли пояснити, чому ви використовували "бокс", а не "кастинг"? Що тут відбувається бокс? Чи виділяються / розміщуються об'єкти?
Бенджамін Груенбаум

2
@BenjaminGruenbaum Ви праві, що кастинг був би більш загальним. Це означає, що реальна різниця під час виконання полягає в тому, що ви маєте справу з типами значень (саме це я припускав, коли писав "бокс"). Для референтних типів поведінка фактично така ж, як і ArrayListпід час виконання. Статично, однак, він потребує акторського складу ArrayList.
Мехрдад Афшарі

Мені було цікаво, чи має фреймворк обмежувати T типу "об'єктного" типу, оскільки ArrayList це явно дозволяє.
rajibdotnet

Щодо знецінення нетипізованих колекцій, дивіться у розділі " Генерики, які вважаються шкідливими"
Ant_222

@ Ant_222, цей блог був написаний майже 15 років тому. Я думаю, що дані останніх десятиліть + показали, що дженерики не є шкідливими. :)
Скотт Адамс

101

Використовуючи це, 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, щоб уникнути помилок лиття. Зараз днями люди використовують об’єкт, що робить ArrayList більше не потрібним.
Переключення

1
я +1 до виправдання, але ви все одно можете зробити, якщо (num є int) {} до вашого списку масивів, щоб уникнути помилок
Міна Габріель,

Запобігайте помилкам лиття та накладних боксах. Досить багато причин для дженериків загалом.
марш

26

Додати до вищезазначених пунктів. Використання ArrayListв 64-бітної операційній системі займає в 2 рази більше пам'яті, ніж використання в 32-бітної операційній системі. Тим часом загальний список List<T>використовує набагато менше пам'яті, ніж the ArrayList.

наприклад, якщо ми використовуємо 19 ArrayListМб у 32-бітовому режимі, це займе 39 МБ у 64-бітному. Але якщо у вас є загальний список List<int>8MB в 32-розрядному, він зайняв би лише 8,1MB в 64-розрядному, що є колосальним 481% різницею порівняно з ArrayList.

Джерело: Загальний список ArrayList для примітивних типів та 64-бітних


5
це справедливо лише для зберігання типів значень, а не типів посилань. відмінність пов’язана з тим, що архівник може містити лише покажчики, а самі дані потрібно зберігати в іншому місці. З іншого боку, типи значень можуть зберігатися безпосередньо у списку.
Расмус Дамгаард Нільсен

19

Ще одна різниця, яку слід додати, стосується синхронізації потоків.

ArrayListзабезпечує деяку безпеку потоків через властивість Synchronized, яка повертає захисну нитку обгортку навколо колекції. Обгортка працює, блокуючи всю колекцію під час кожного додавання або видалення. Тому кожен потік, який намагається отримати доступ до колекції, повинен дочекатися своєї черги, щоб зняти один замок. Це не масштабується і може призвести до значної погіршення продуктивності для великих колекцій.

List<T>не забезпечує жодної синхронізації потоку; код користувача повинен забезпечувати всю синхронізацію, коли елементи додаються або видаляються на декількох потоках одночасно.

Більше інформації тут Синхронізація ниток у .Net Framework


Я не кажу, що вам слід користуватися, ArrayListякщо цього можна уникнути, але це дурна причина. Зрештою, обгортка абсолютно не є обов'язковою; якщо вам не потрібно блокування або якщо вам потрібен більш детальний контроль, не використовуйте обгортку.
Торарін

1
Якщо ви хочете забезпечити безпеку потоків, я пропоную розглянути простір імен System.Collections.Concurrent, перш ніж розглядати ArrayList.
Ykok

15

Проста відповідь:

ArrayList не є загальним

  • Це тип об'єкта, тому ви можете зберігати в ньому будь-який тип даних.
  • Ви можете зберігати будь-які значення (тип значення або тип посилання), такі рядки, int, службовці та об'єкти в ArrayList. (Примітка та)
  • Бокс та Unboxing відбудуться.
  • Не тип безпечний.
  • Це старше.

Список загальний

  • Це тип типу, тому ви можете вказати T під час виконання.
  • Ви можете зберігати єдине значення типу T (рядок, int, співробітник або об'єкт) на основі декларації. (Примітка або)
  • Бокс та Unboxing не відбудуться.
  • Тип сейф.
  • Це новіше.

Приклад:

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/




2

Ефективність уже згадується в кількох відповідях як диференціюючий фактор, але для вирішення питання « Наскільки повільніше ArrayList? "Та" Чому це загально повільніше? ", Подивіться нижче.

Щоразу, коли типи значень використовуються як елементи, продуктивність різко падає ArrayList. Розглянемо випадок простого додавання елементів. Зважаючи на те, що бокс триває - оскільки ArrayListдодавання приймає лише objectпараметри - збирач сміття викликає набагато більше роботи, ніж з List<T>.

На скільки різниця у часі? Принаймні в кілька разів повільніше, ніж при List<T>. Просто погляньте на те, що відбувається з кодом, який додає значення до 10 міль int до ArrayListvs 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 сміттєзбірників.


1

Я думаю, відмінності між ArrayListі List<T>є:

  1. List<T>, де T - значення типу швидше, ніж ArrayList. Це відбувається тому, що ви List<T>уникаєте боксу / розпакування (де T - значення типу).
  2. Багато джерел кажуть - зазвичай ArrayListвикористовується просто для зворотної сумісності. (це не реальна різниця, але я думаю, що це важливо зауважити).
  3. Відображення легше з негенерічним ArrayListтодіList<T>
  4. 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
  5. 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)
        {
            // ...
        }
    }

0

Як зазначено в документації .NET Framework

Ми не рекомендуємо використовувати ArrayListклас для нової розробки. Натомість радимо скористатись загальним List<T> класом. ArrayListКлас призначений для зберігання різнорідних колекцій об'єктів. Однак це не завжди пропонує найкращі показники. Натомість рекомендуємо:

  • Для неоднорідної колекції об’єктів використовуйте тип List<Object>(у C #) або List(Of Object)(у Visual Basic).
  • Для однорідної колекції предметів використовуйте List<T>клас.

Див. Також Колекції, що не є загальними, не слід використовувати

таблиця показує, як типи колекцій, що не є загальними, можуть бути замінені їх загальними аналогами


-2

Використовуючи "Список", ви можете запобігти помилкам введення. Це дуже корисно, щоб уникнути помилки лиття під час виконання.

Приклад:

Тут (за допомогою 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.
        }
    }

Що це додає поза термінами відповіді, наданими на три роки раніше? Він має майже той самий текст дослівно, без посилання на джерело, без належного форматування тощо.
Дуглас Заре

-3

Для мене це все про знання ваших даних. Якщо я продовжую розширювати свій код на основі ефективності, мені доведеться вибрати параметр "Список" як спосіб розшифровки моїх даних без зайвого кроку, коли завжди цікавляться типи, особливо "Спеціальні типи". Якщо машина розуміє різницю і може визначитись із тим, з яким типом даних я справді маю справу, то чому я повинен заважати і витрачати час на рух за цирацій визначення "ЯКЩО ІНШЕ"? Моя філософія полягає в тому, щоб дозволити машині працювати для мене, а не мені працювати на машині? Знання унікальних відмінностей різних команд кодового коду проходить довгий шлях у тому, щоб зробити ваш код максимально ефективним.

Том Джонсон (один вхід ... один вихід)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.