It is rare, in reality, that you would want to use an array. Definitely use a List<T> any time you want to add/remove data, since resizing arrays is expensive. If you know the data is fixed length, and you want to micro-optimise for some very specific reason (after benchmarking), then an array may be useful.
List<T> offers a lot more functionality than an array (although LINQ evens it up a bit), and is almost always the right choice. Except for params arguments, of course. ;-p
As a counter - List<T> is one-dimensional; where-as you have have rectangular (etc) arrays like int[,] or string[,,] - but there are other ways of modelling such data (if you need) in an object model.
Use an array when you are dealing with data that is:
fixed in size, or unlikely to grow much
suitably large (more than 10, 50, 100 elements, depending on the algorithm)
you will be doing lots of indexing into it, i.e. you know you will often want the third element, or the fifth, or whatever.
Use a list for:
variable length data lists
that are mostly used as a stack or a queue or need to be iterated in its entirety
when you do not want to write an expression to derive the ultimate array size for the declaration and you do not want to wastefully pick a large number
Use a hashmap for:
variable length data lists
that need to be indexed like an array would
In reality, you'll want a list or hashmap almost all of the time. Next time you pick a data structure, think about what it must do well for you (or your code, anyway). Then pick something based on that. When in doubt, pick something as general as possible, i.e. an interface you can replace the implementation of quite easily. Some good links in the other answers as well.
Another situation not yet mentioned is when one will have a large number of items, each of which consists of a fixed bunch of related-but-independent variables stuck together (e.g. the coordinates of a point, or the vertices of a 3d triangle). An array of exposed-field structures will allow the its elements to be efficiently modified "in place"--something which is not possible with any other collection type. Because an array of structures holds its elements consecutively in RAM, sequential accesses to array elements can be very fast. In situations where code will need to make many sequential passes through an array, an array of structures may outperform an array or other collection of class object references by a factor of 2:1; further, the ability to update elements in place may allow an array of structures to outperform any other kind of collection of structures.
Although arrays are not resizable, it is not difficult to have code store an array reference along with the number of elements that are in use, and replace the array with a larger one as required. Alternatively, one could easily write code for a type which behaved much like a List<T> but exposed its backing store, thus allowing one to say either MyPoints.Add(nextPoint); or MyPoints.Items[23].X += 5;. Note that the latter would not necessarily throw an exception if code tried to access beyond the end of the list, but usage would otherwise be conceptually quite similar to List<T>.
If I know exactly how many elements I'm going to need, say I need 5 elements and only ever 5 elements then I use an array. Otherwise I just use a List<T>.
So, if you are writing method that accepts one as an argument but uses only limited aspect, you may be able to declare it as IList<MyClass> for callers' convenience. (e.g. Foo(IList<int> foo) can be called like Foo(new[] { 1, 2, 3 }) or Foo(new List<int> { 1, 2, 3 }) )
Arrays should be used in preference to List when the immutability of the collection itself is part of the contract between the client & provider code (not necessarily immutability of the items within the collection) AND when IEnumerable is not suitable.
For example,
var str = "This is a string";
var strChars = str.ToCharArray(); // returns array
It is clear that modification of "strChars" will not mutate the original "str" object, irrespective implementation-level knowledge of "str"'s underlying type.
But suppose that
var str = "This is a string";
var strChars = str.ToCharList(); // returns List<char>
strChars.Insert(0, 'X');
In this case, it's not clear from that code-snippet alone if the insert method will or will not mutate the original "str" object. It requires implementation level knowledge of String to make that determination, which breaks Design by Contract approach. In the case of String, it's not a big deal, but it can be a big deal in almost every other case. Setting the List to read-only does help but results in run-time errors, not compile-time.
It is rare, in reality, that you would want to use an array. Definitely use a
List<T>
any time you want to add/remove data, since resizing arrays is expensive. If you know the data is fixed length, and you want to micro-optimise for some very specific reason (after benchmarking), then an array may be useful.List<T>
offers a lot more functionality than an array (although LINQ evens it up a bit), and is almost always the right choice. Except forparams
arguments, of course. ;-pAs a counter -
List<T>
is one-dimensional; where-as you have have rectangular (etc) arrays likeint[,]
orstring[,,]
- but there are other ways of modelling such data (if you need) in an object model.See also:
That said, I make a lot of use of arrays in my protobuf-net project; entirely for performance:
byte[]
is pretty much essential for encoding;byte[]
buffer which I fill before sending down to the underlying stream (and v.v.); quicker thanBufferedStream
etc;Foo[]
rather thanList<Foo>
), since the size is fixed once built, and needs to be very fast.But this is definitely an exception; for general line-of-business processing, a
List<T>
wins every time.Use an array when you are dealing with data that is:
Use a list for:
Use a hashmap for:
In reality, you'll want a list or hashmap almost all of the time. Next time you pick a data structure, think about what it must do well for you (or your code, anyway). Then pick something based on that. When in doubt, pick something as general as possible, i.e. an interface you can replace the implementation of quite easily. Some good links in the other answers as well.
Another situation not yet mentioned is when one will have a large number of items, each of which consists of a fixed bunch of related-but-independent variables stuck together (e.g. the coordinates of a point, or the vertices of a 3d triangle). An array of exposed-field structures will allow the its elements to be efficiently modified "in place"--something which is not possible with any other collection type. Because an array of structures holds its elements consecutively in RAM, sequential accesses to array elements can be very fast. In situations where code will need to make many sequential passes through an array, an array of structures may outperform an array or other collection of class object references by a factor of 2:1; further, the ability to update elements in place may allow an array of structures to outperform any other kind of collection of structures.
Although arrays are not resizable, it is not difficult to have code store an array reference along with the number of elements that are in use, and replace the array with a larger one as required. Alternatively, one could easily write code for a type which behaved much like a
List<T>
but exposed its backing store, thus allowing one to say eitherMyPoints.Add(nextPoint);
orMyPoints.Items[23].X += 5;
. Note that the latter would not necessarily throw an exception if code tried to access beyond the end of the list, but usage would otherwise be conceptually quite similar toList<T>
.If I know exactly how many elements I'm going to need, say I need 5 elements and only ever 5 elements then I use an array. Otherwise I just use a List<T>.
Since no one mention: in C#, an array is a list.
MyClass[]
andList<MyClass>
both implementIList<MyClass>
.So, if you are writing method that accepts one as an argument but uses only limited aspect, you may be able to declare it as
IList<MyClass>
for callers' convenience. (e.g.Foo(IList<int> foo)
can be called likeFoo(new[] { 1, 2, 3 })
orFoo(new List<int> { 1, 2, 3 })
)Details:
Arrays should be used in preference to List when the immutability of the collection itself is part of the contract between the client & provider code (not necessarily immutability of the items within the collection) AND when IEnumerable is not suitable.
For example,
It is clear that modification of "strChars" will not mutate the original "str" object, irrespective implementation-level knowledge of "str"'s underlying type.
But suppose that
In this case, it's not clear from that code-snippet alone if the insert method will or will not mutate the original "str" object. It requires implementation level knowledge of String to make that determination, which breaks Design by Contract approach. In the case of String, it's not a big deal, but it can be a big deal in almost every other case. Setting the List to read-only does help but results in run-time errors, not compile-time.