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.
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.
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.