Resolved Why can't you supply the array to a List<>?

Alexander Freyr

New member
Joined
Dec 30, 2020
Messages
2
Programming Experience
3-5
Since List<> is just a wrapper around an array why can't I supply the array through the constructor? It only allows a collection which is relatively expensive opposed to just handing it an array directly.
 
Solution
It only allows a collection
That is false. The parameter of the List<T> constructor is type IEnumerable<T>. That means that you can pass any enumerable list as an argument. That pretty much means that anything that can be the subject of a foreach loop can be passed as an argument to that constructor. Can an array be the subject of a foreach loop? Yes it can, so an array can be passed as an argument to that constructor.

That said, even though you can pass an array to the constructor, that won't be the array that actually gets wrapped. The reason that any object that implements IEnumerable<T> can be provided is that, inside that constructor, that object is enumerated and its items added to an array...
It only allows a collection
That is false. The parameter of the List<T> constructor is type IEnumerable<T>. That means that you can pass any enumerable list as an argument. That pretty much means that anything that can be the subject of a foreach loop can be passed as an argument to that constructor. Can an array be the subject of a foreach loop? Yes it can, so an array can be passed as an argument to that constructor.

That said, even though you can pass an array to the constructor, that won't be the array that actually gets wrapped. The reason that any object that implements IEnumerable<T> can be provided is that, inside that constructor, that object is enumerated and its items added to an array created by the constructor. One reason for that should be fairly obvious. If you were able to pass in an array and the List<T> just wrapped that, you would then be able to manipulate that array from outside the List<T> object. A List<T> is supposed to be a self-contained object so you should not be able to manipulate its contents without a reference to it.

Apart from that, the fact that it is a wrapper for an array is just an implementation detail and should be irrelevant to its usage. If they were to find a more efficient way to implement the List<T> class in the future, they should be able to change the implementation without affecting any code that uses the class. If they let you pass an array in on the assumption that that array would be the actual internal data store, any such implementation change would break any code that made use of that assumption.

I should clarify something I said earlier. In actual fact, a foreach loop only requires that an object implement the IEnumerable interface. Generics weren't introduced until .NET 2.0 so, for the first two versions, IEnumerable was all there was. That's why lots of collections that were implemented from the start only provide an object reference to their items when enumerated, e.g. Control.Controls, DataTable.Rows, ArrayList, etc, etc. Even arrays only implemented IEnumerable at that stage. You would need to explicitly declare the type of the loop control variable when enumerating such a list, e.g.
C#:
string[] names;

// ...

foreach (string name in names)
{
    // ...
}
From .NET 2.0 onwards, all enumerable lists should, if at all possible, implement both IEnumerable and IEnumerable<T>. The implementation of arrays was changed to do just that. Now the type of the loop control variable can be inferred, e.g.
C#:
string[] names;

// ...

foreach (var name in names)
{
    // ...
}
Even now, if you use an object that only implements IEnumerable and not IEnumerable<T> as the source for a foreach, you still have to declare the type explicitly, like in the first code snippet.

Given that the List<T> class itself is generic though, it should be fairly obvious why the constructor requires the generic IEnumerable<T> interface, i.e. the items passed in must of the type that the list can store.
 
Last edited:
Solution

Latest posts

Back
Top Bottom