86

As a new .NET 3.5 programmer, I started to learn LINQ and I found something pretty basic that I haven't noticed before:

The book claims every array implements IEnumerable<T> (obviously, otherwise we couldn't use LINQ to objects on arrays...). When I saw this, I thought to myself that I never really thought about that, and I asked myself what else all arrays implement - so I examined System.Array using the object browser (since it's the base class for every array in the CLR) and, to my surprise, it doesn't implement IEnumerable<T>.

So my question is: where is the definition? I mean, how can I tell exactly which interfaces every array implements?

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
ET.
  • 1,899
  • 2
  • 18
  • 28

5 Answers5

84

From the documentation (emphasis mine):

[...] the Array class implements the System.Collections.Generic.IList<T>, System.Collections.Generic.ICollection<T>, and System.Collections.Generic.IEnumerable<T> generic interfaces. The implementations are provided to arrays at run time, and therefore are not visible to the documentation build tools.

EDIT: as Jb Evain points out in his comment, only vectors (one-dimensional arrays) implement the generic interfaces. As to why multi-dimensional arrays don't implement the generic interfaces, I'm not quite sure since they do implement the non-generic counterparts (see the class declaration below).

The System.Array class (i.e. every array) also implements these non-generic interfaces:

public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • 3
    I would say: inherits this non-generic class, thus implements these non-generic interfaces – abatishchev Dec 19 '10 at 10:48
  • I hate to ask silly questions, then I really try to find my answer on MSDN first. This time I missed it... sorry for the trouble and thanks for the help. – ET. Dec 19 '10 at 10:48
  • 5
    I didn't downvote, but only vectors (one dimensional arrays) type implement the generic interfaces. A multi dimensional array type doesn't implement them. – Jb Evain Dec 19 '10 at 13:24
  • @Jb Evain: Good point! It's also worth noting that jagged arrays do. – Hosam Aly Dec 19 '10 at 15:28
  • 3
    @Hosam Aly: Jagged arrays are nothing more than vectors who happen to contain other vectors. So there's no surprise here. – Jb Evain Dec 20 '10 at 12:11
82

You can find the answer to your question empirically using a small code snippet:

foreach (var type in (new int[0]).GetType().GetInterfaces())
    Console.WriteLine(type);

Running the above snippet would result in the following output (on .NET 4.0):

System.ICloneable
System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]

(`1 means <T>)

After .NET 4.5 (.NET Standard 1.0 and later), there's two additional interfaces:

System.Collections.Generic.IReadOnlyList`1[System.Int32]
System.Collections.Generic.IReadOnlyCollection`1[System.Int32]
Snak
  • 673
  • 1
  • 5
  • 19
Hosam Aly
  • 41,555
  • 36
  • 141
  • 182
  • 14
    +1, though I would have used `typeof(int[])` rather than `(new int[0].GetType()`... – Thomas Levesque Dec 19 '10 at 11:20
  • 1
    I like this. Also supports the quote from the MSDN docs (compare this with the output of iterating through `typeof(Array).GetType().GetInterfaces()`, where the generic implementations are missing). – BoltClock Dec 19 '10 at 11:22
  • 17
    @Thomas: Thanks for the suggestion. I preferred to use `(new int[0]).GetType()` to make sure the result includes any *implementations provided to arrays at runtime*, as mentioned by @BoltClock. – Hosam Aly Dec 19 '10 at 11:31
  • Note that in .NET 4.5 (.NET Standard 1.0) they introduced two more, IReadOnlyList and IReadOnlyCollection. – Snak Jun 19 '19 at 09:08
57

Starting with .NET 4.5, arrays also implement the interfaces System.Collections.Generic.IReadOnlyList<T> and System.Collections.Generic.IReadOnlyCollection<T>.

Thus, when using .NET 4.5, the complete list of interfaces implemented by arrays becomes (obtained using the method presented in Hosam Aly's answer):

System.Collections.IList
System.Collections.ICollection
System.Collections.IEnumerable
System.Collections.IStructuralComparable
System.Collections.IStructuralEquatable
System.Collections.Generic.IList`1[System.Int32]
System.Collections.Generic.ICollection`1[System.Int32]
System.Collections.Generic.IEnumerable`1[System.Int32]
System.Collections.Generic.IReadOnlyList`1[System.Int32]
System.Collections.Generic.IReadOnlyCollection`1[System.Int32]

Strangely, it seems that it was forgotten to update the documentation on MSDN to mention these two interfaces.

Community
  • 1
  • 1
cr7pt0gr4ph7
  • 1,244
  • 13
  • 19
  • 1
    Your linked [documentation](http://msdn.microsoft.com/en-us/library/system.array.aspx) contains this information, but a bit hidden: _"Starting with the .NET Framework 2.0, the `Array` class implements the `System.Collections.Generic.IList`, `System.Collections.Generic.ICollection`, and `System.Collections.Generic.IEnumerable` generic interfaces. The implementations are provided to arrays at run time, and as a result, the generic interfaces do not appear in the declaration syntax for the Array class."_ – Tim Schmelter Feb 26 '16 at 14:21
1

Carefully on array interfaces, they may implement them but actually they don't really do this... Take a loon on the following code:

            var x = new int[] { 1, 2, 3, 4, 5 };
        var y = x as IList<int>;
        Console.WriteLine("The IList:" + string.Join(",", y));
        try
        {
            y.RemoveAt(1);
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        Console.WriteLine(string.Join(",", y));

It produces the following output: result

So parsing works but not everything is supported which is correct from fixed length collection perspective but quite wrong if you really believe that it is a list. There goes Liskov principle from SOLID :(.

For testing fast this will help.

Adrian P.
  • 31
  • 1
  • 6
  • Brilliant point. I can see Microsoft's point of view, in that an array has a "Count", and is indexable. But you're right, it can't implement RemoveAt(x) because that would mean re-dimensioning the array. I guess that would be possible, as references to a variable can be moved by the CLR. - and without it, indeed Liskov substitution is out of the window. The solution I guess would be to break down IList into IFixedList and IFlexibleList, and have Array implement only the IFixedList. Still, I see the casting as a convenience in most cases. – Simon Miller Oct 25 '18 at 10:30
  • Actually the IList interface also has a property via ICollection called IsReadOnly. A IList implementation is therefor not required to actually handle the calls that manipulate the collection if IsReadOnly is returned as true, which it is for an Array. – Kasper Cottaar Apr 30 '19 at 12:58
0

I have found the implementation of the IList<T>, ICollection<T>, IEnumerable<T> in the SZArrayHelper nested class of the Array.

But i have to warn you - there you will find much more questions...

The refference

After that i got only one - there_is_no_array ;)

Kamerton
  • 315
  • 3
  • 9