What interfaces do all arrays implement in C#?
Asked Answered
R

5

88

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?

Rhodolite answered 19/12, 2010 at 10:39 Comment(0)
N
85

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
Nanna answered 19/12, 2010 at 10:42 Comment(5)
I would say: inherits this non-generic class, thus implements these non-generic interfacesCephalo
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.Rhodolite
I didn't downvote, but only vectors (one dimensional arrays) type implement the generic interfaces. A multi dimensional array type doesn't implement them.Isomerize
@Jb Evain: Good point! It's also worth noting that jagged arrays do.Mercurous
@Hosam Aly: Jagged arrays are nothing more than vectors who happen to contain other vectors. So there's no surprise here.Isomerize
M
83

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]
Mercurous answered 19/12, 2010 at 11:18 Comment(4)
+1, though I would have used typeof(int[]) rather than (new int[0].GetType()...Rodneyrodolfo
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).Nanna
@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.Mercurous
Note that in .NET 4.5 (.NET Standard 1.0) they introduced two more, IReadOnlyList and IReadOnlyCollection.Keniakenilworth
S
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.

Spurling answered 4/8, 2013 at 11:24 Comment(1)
Your linked documentation contains this information, but a bit hidden: "Starting with the .NET Framework 2.0, 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 as a result, the generic interfaces do not appear in the declaration syntax for the Array class."Adenoidectomy
Y
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.

Yellowish answered 23/1, 2018 at 13:58 Comment(2)
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.Spoiler
Actually the IList<T> interface also has a property via ICollection<T> called IsReadOnly. A IList<T> 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.Particiaparticipant
A
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 ;)

Ashford answered 3/4, 2018 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.