494

What is the difference between ArrayList and List<> in C#?

Is it only that List<> has a type while ArrayList doesn't?

Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
scatman
  • 14,109
  • 22
  • 70
  • 93
  • 7
    possible duplicate of [ArrayList vs List](http://stackoverflow.com/questions/391088/arraylist-vs-listobject) – John Saunders Nov 22 '10 at 23:21
  • 9
    It's a close question, but I think not exactly duplicate. This asks about `List<>` in general, while that one asks about `List` specifically – goodeye Jun 03 '15 at 03:55
  • Found this very helpful blog, it might help. Thought I should share the link: http://fintechexplained.blogspot.co.uk/2017/07/data-structures-comparison.html – InfoLearner Jul 21 '17 at 22:33

12 Answers12

631

Yes, pretty much. List<T> is a generic class. It supports storing values of a specific type without casting to or from object (which would have incurred boxing/unboxing overhead when T is a value type in the ArrayList case). ArrayList simply stores object references. As a generic collection, List<T> implements the generic IEnumerable<T> interface and can be used easily in LINQ (without requiring any Cast or OfType call).

ArrayList belongs to the days that C# didn't have generics. It's deprecated in favor of List<T>. You shouldn't use ArrayList in new code that targets .NET >= 2.0 unless you have to interface with an old API that uses it.

PJSimon
  • 343
  • 1
  • 18
Mehrdad Afshari
  • 414,610
  • 91
  • 852
  • 789
  • Would you mind explaining why you used "boxing" and not "casting"? What boxing happens here? Are objects allocated/deallocated? – Benjamin Gruenbaum Nov 07 '13 at 19:54
  • 3
    @BenjaminGruenbaum You are correct that casting would be more general. That said, the real difference at runtime is when you're dealing with value types (which is what I assumed when I wrote "boxing"). For reference types, the behavior is effectively the same as `ArrayList` at runtime. Statically though, it'll require a cast with `ArrayList`. – Mehrdad Afshari Nov 08 '13 at 08:40
  • I was wondering whether framework should restrict T to be of "object" type, since ArrayList implicitly allows that. – rajibdotnet Sep 16 '17 at 13:38
  • I'd like to (belatedly) add to @ScottAdams point: that blog talks about issues with Java 5's implementation of generics, which is different enough from .NET's implementation that it's just not relevant to this question. Neither of the "harmful" examples mentioned in the post are problematic in .NET, so if you want to talk about the "gotchas" of .NET generics, you'll want to use a different source. – David Schwartz Jul 16 '20 at 03:31
  • boxing and unboxing refers to casting (boxing is implicit and unboxing is explicit). When a value is boxed, it gets stored on the heap and uses more memory. It requires more time to unbox a value. Generally boxing/unboxing should be avoid if possible. you can read more here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing – NeoH4x0r Sep 10 '21 at 22:14
123

Using List<T> you can prevent casting errors. It is very useful to avoid a runtime casting error.

Example:

Here (using ArrayList) you can compile this code but you will see an execution error later.

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
}

If you use List, you avoid these errors:

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

Reference: MSDN

Miral
  • 12,637
  • 4
  • 53
  • 93
termas
  • 1,339
  • 1
  • 8
  • 3
  • You can check the type when you pull from the ArrayList to prevent casting errors. Now days people use object, making ArrayList no longer needed. – Chizl Mar 26 '13 at 12:30
  • 2
    i +1 to the justification but you still can do if(num is int){} to your array list to avoid errors – Mina Gabriel Feb 23 '14 at 02:56
  • 1
    Prevent casting errors and boxing overhead. Pretty much the reasons for generics in general. – marsze Oct 24 '18 at 08:01
34

To add to the above points. Using ArrayList in 64bit operating system takes 2x memory than using in the 32bit operating system. Meanwhile, generic list List<T> will use much low memory than the ArrayList.

for example if we use a ArrayList of 19MB in 32-bit it would take 39MB in the 64-bit. But if you have a generic list List<int> of 8MB in 32-bit it would take only 8.1MB in 64-bit, which is a whooping 481% difference when compared to ArrayList.

Source: ArrayList’s vs. generic List for primitive types and 64-bits

Anoop
  • 849
  • 3
  • 13
  • 28
  • 8
    that is only true for storing value types, not reference types. the difference is due to the fact that a arraylist can only contain pointers, and the data itself need to be stored elsewhere. On the other hand, value types can be stored directly in a list. – Rasmus Damgaard Nielsen Nov 03 '15 at 07:20
22

Another difference to add is with respect to Thread Synchronization.

ArrayList provides some thread-safety through the Synchronized property, which returns a thread-safe wrapper around the collection. The wrapper works by locking the entire collection on every add or remove operation. Therefore, each thread that is attempting to access the collection must wait for its turn to take the one lock. This is not scalable and can cause significant performance degradation for large collections.

List<T> does not provide any thread synchronization; user code must provide all synchronization when items are added or removed on multiple threads concurrently.

More info here Thread Synchronization in the .Net Framework

NullReference
  • 2,828
  • 2
  • 30
  • 33
  • I'm not saying you should use `ArrayList` if it can be avoided, but this is a silly reason. The wrapper is entirely optional after all; if you don't need locking or if you need more granular control, don't use the wrapper. – Thorarin Oct 05 '17 at 23:05
  • 1
    If you want thread-safety I suggest looking at the System.Collections.Concurrent namespace before considering ArrayList. – Ykok Nov 16 '17 at 14:26
21

Simple Answer is,

ArrayList is Non-Generic

  • It is an Object Type, so you can store any data type into it.
  • You can store any values (value type or reference type) such string, int, employee and object in the ArrayList. (Note and)
  • Boxing and Unboxing will happen.
  • Not type safe.
  • It is older.

List is Generic

  • It is a Type of Type, so you can specify the T on run-time.
  • You can store an only value of Type T (string or int or employee or object) based on the declaration. (Note or)
  • Boxing and Unboxing will not happen.
  • Type safe.
  • It is newer.

Example:

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

Please read the Microsoft official document: https://blogs.msdn.microsoft.com/kcwalina/2005/09/23/system-collections-vs-system-collection-generic-and-system-collections-objectmodel/

enter image description here

Note: You should know Generics before understanding the difference: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/

Aravin
  • 6,605
  • 5
  • 42
  • 58
5

Performance has already been mentioned in several answers as a differentiating factor, but to address the “How much slower is the ArrayList ?” and “Why is it slower overall ?”, have a look below.

Whenever value types are used as elements, performance drops dramatically with ArrayList. Consider the case of simply adding elements. Due to the boxing going on - as ArrayList’s Add only takes object parameters - the Garbage Collector gets triggered into performing a lot more work than with List<T>.

How much is the time difference ? At least several times slower than with List<T>. Just take a look at what happens with code adding 10 mil int values to an ArrayList vs List<T>: enter image description here

That’s a run time difference of 5x in the ‘Mean’ column, highlighted in yellow. Note also the difference in the number of garbage collections done for each, highlighted in red (no of GCs / 1000 runs).

Using a profiler to see what’s going on quickly shows that most of the time is spent doing GCs, as opposed to actually adding elements. The brown bars below represent blocking Garbage Collector activity: enter image description here

I’ve written a detailed analysis of what goes on with the above ArrayList scenario here https://mihai-albert.com/2019/12/15/boxing-performance-in-c-analysis-and-benchmark/.

Similar findings are in “CLR via C#” by Jeffrey Richter. From chapter 12 (Generics):

[…] When I compile and run a release build (with optimizations turned on) of this program on my computer, I get the following output.

00:00:01.6246959 (GCs= 6) List<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 String

The output here shows that using the generic List algorithm with the Int32 type is much faster than using the non-generic ArrayList algorithm with Int32. In fact, the difference is phenomenal: 1.6 seconds versus almost 11 seconds. That’s ~7 times faster! In addition, using a value type (Int32) with ArrayList causes a lot of boxing operations to occur, which results in 390 garbage collections. Meanwhile, the List algorithm required 6 garbage collections.

Mihai Albert
  • 1,288
  • 1
  • 12
  • 27
4

ArrayList is the collections of different types data whereas List<> is the collection of similar type of its own depedencties.

Jibin Balachandran
  • 3,381
  • 1
  • 24
  • 38
3

ArrayList are not type safe whereas List<T> are type safe. Simple :).

Felipe Augusto
  • 7,733
  • 10
  • 39
  • 73
Hassan Rahman
  • 4,953
  • 1
  • 34
  • 32
3

As mentioned in .NET Framework documentation

We don't recommend that you use the ArrayList class for new development. Instead, we recommend that you use the generic List<T> class. The ArrayList class is designed to hold heterogeneous collections of objects. However, it does not always offer the best performance. Instead, we recommend the following:

  • For a heterogeneous collection of objects, use the List<Object> (in C#) or List(Of Object) (in Visual Basic) type.
  • For a homogeneous collection of objects, use the List<T> class.

See also Non-generic collections shouldn't be used

table shows how the non-generic collection types can be replaced by their generic counterparts

ElasticCode
  • 7,311
  • 2
  • 34
  • 45
1

I think, the differences between ArrayList and List<T> are:

  1. List<T>, where T is value-type is faster than ArrayList. This is because List<T> avoids boxing/unboxing (where T is value-type).
  2. Many sources say - usually ArrayList used just for backward compatibility. (is not a real difference, but i think it is important note).
  3. Reflection is easier with nongeneric ArrayList then List<T>
  4. ArrayList has IsSynchronized property. So, It is easy to create and use syncronised ArrayList. I didin't found IsSynchronized property for List<T>. Also Keep in mind this type of synchronization is relatively inefficient, 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 has ArrayList.SyncRoot property which can be used for syncronisation (msdn). List<T> hasn't SyncRoot property, so in the following construction you need to use some object if you use List<T>:

    ArrayList myCollection = new ArrayList();
    lock(myCollection.SyncRoot) //  ofcourse you can use another object for this goal
    {
        foreach (object item in myCollection)
        {
            // ...
        }
    }
    
Maxim Kitsenko
  • 2,042
  • 1
  • 20
  • 43
-2

Using "List" you can prevent casting errors. It is very useful to avoid a runtime casting error.

Example:

Here (using ArrayList) you can compile this code but you will see an execution error later.

    // 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.
        }
    }
Si8
  • 9,141
  • 22
  • 109
  • 221
Deepak
  • 121
  • 5
  • What does this add beyond the answer termas gave three years earlier? It has almost the same text verbatim, without linking to the source, without formatting properly, etc. – Douglas Zare Jun 17 '16 at 23:48
-3

To me its all about knowing your data. If I am continuing to expand my code on the basis of efficiency, I would have to choose the List option as a way of deciphering of my data w/o the unnecessary step of always wondering about types, especially 'Custom Types'. If the machine understands the difference and can determine on it's on what type of data I'm actually dealing with then why should I get in the way and waste time going thru the gyrations of 'IF THEN ELSE' determinations? My philosophy is to let the machine work for me instead of me working on the machine? Knowing the unique differences of different object code commands goes a long way in making your code as efficient.

Tom Johnson (One Entry ... One Exit)