Let me help you differentiate between arrays and lists more properly.
Arrays are a system-wide low level data structures to let you have series of data of the same type. All arrays have Length property which determines their allocated size. You can think of them as a substitute for having to write a multitude of variables
int myInt0 = 5;
int myInt1 = 15;
int myInt2 = 2;
Debug.Log(myInt1);
turns into
int[] myInt = new int[] { 5, 15, 2 };
Debug.Log(myInt[1]);
Much more compact and versatile, especially as the series grow into hundreds of items.
Lists are similar, however, these are dedicated collections which solve some of the shortcomings of how arrays operate.
Here are some things you cannot do with arrays:
- have a dynamic size of items during runtime
- insert an item
- remove an item
You may consider Lists being high-level representations of arrays with additional functionality.
Lists, being true collections, specify methods such as Add, Clear, Contains, and Remove.
Arrays only act like they implement interfaces IList, ICollection, and IEnumerable, for convenience, even though they don’t directly support Add or Remove, as an example. But they can still be accessed through indexers [n]
and iterated over. This helps when you want to pass a compatible data structure as an argument, regardless of whether it’s a list or an array.
void myFunc(IList list) { ... }
var myArray = new int[15];
var myList = new List<int>();
myFunc(myArray);
myFunc(myList);
It’s worth noting that a List still expresses itself through arrays under the hood, because it simply allocates chunks of arrays and knows how to produce a continuity between them. This is something you can control with Capacity. By stating Capacity you can limit your list’s maximum size, but normally this is not required.
Where this knowledge pays off is when your list is supposed to dramatically change in size. Because it will allocate arrays in advance, a growing list will double in allocation size once it hits its internal limit. Then when you remove the items from it, the vacant arrays stay in place to prevent extra work, even if you now have just 2 items and the capacity was in thousands. You can use TrimExcess punctually to get rid of this unused memory allocation.
Observe that Length doesn’t make much sense in the context of lists, because they allocate much more dynamically, it’s not just a single series of data. Instead, lists provide their own counter, called Count. It comes from the ICollection interface and will work in the previous example as well.
void myFunc(IList list) {
Debug.Log(list.Count);
}
var myArray = new int[15];
myFunc(myArray); // prints 15
This is weird right, why does this work? Well arrays get retrofitted with all these interfaces during runtime, and Count rewires to Length when arrays are used like this. This will not work however
var myArray = new int[15];
Debug.Log(myArray.Count); // error
Because the compiler runs before the runtime, it cannot make any sense of it.
All in all, use arrays when you need tight control over allocation, when you don’t need to change the length of data, or when you yourself are building a collection of your own. Use lists for everything else, namely for high level logic and user data.
And remember that every high level collection supplies Count. The only data structure that has Length is an array, this is a reflection of how fundamental it is for the whole system. It is not a workaround.