2

What makes .Net IEnumerable so special that compiler types like arrays can be passed as an argument in its place with it being a class library interface. Is there some sort of inheritance in the background?

What actually happens when an array can interchangeably replace a collection or IEnumerable as a parameter:

public void DoJob(IEnumerable<Job> jobs)
{
}

Like this method call:

Job job = new Job();
DoJob(new [] { job });
Saleh
  • 150
  • 10
  • 7
    Because arrays implement `IEnumerable`. This is a little like asking "why is a banana a fruit?" – DavidG May 22 '18 at 12:05
  • 5
    `IEnumerable<>` is interface, and array implements this interface, that's all. – Evk May 22 '18 at 12:05
  • 2
    Perhaps an understanding of the Gang of Four iterator pattern will benefit? – StuartLC May 22 '18 at 12:06
  • I come from a Java world so, is a native array declared with `[]` by default a complex type? I know that's the case with other types in .Net. – Saleh May 22 '18 at 12:08
  • 1
    In .NET, that array class is used as an implementation by the compiler, to compile any `[]` usages. See here: https://msdn.microsoft.com/en-us/library/system.array(v=vs.110).aspx – Maarten May 22 '18 at 12:10
  • Possible duplicate of https://stackoverflow.com/questions/2773740/why-do-arrays-in-net-only-implement-ienumerable-and-not-ienumerablet – DavidG May 22 '18 at 12:17

3 Answers3

4

Since you came from Java, I will start by telling you that in C#, there is a unified type system, where every type derives from object, unlike in Java where there are special "primitives".

So in C#, arrays are just another type. Who says they can't implement interfaces? They can! All the compiler provides is some syntax for creating them. In actuality, arrays' type is System.Array.

This is its declaration:

public abstract class Array : ICloneable, IList, ICollection, 
    IEnumerable, IStructuralComparable, IStructuralEquatable

See IEnumerable in there?

EDIT:

For IEnumerable<T>, we can find it in the language spec:

Section 12.1.2:

A one-dimensional array T[] implements the interface System.Collections.Generic.IList (IList for short) and its base interfaces.

IList<T> implements IEnumerable<T>.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • 3
    I don't see `IEnumerable` in there though... ;) – DavidG May 22 '18 at 12:15
  • The array's type is not `System.Array`, as you can see when you examine `typeof(T[])`. But its base type is `System.Array` and it implements some interfaces, including `IEnumerable`. – Dirk May 22 '18 at 12:17
  • Your response is correct, but you forgot the big caveat explained by @Camilo... There is some special trick used by the .NET for arrays. – xanatos May 22 '18 at 12:21
  • I knew that the compiler did something in the background but that explains it, if all it does is just provide a syntax for the Array class with the `[]`. Thanks. – Saleh May 22 '18 at 12:22
  • @DavidG Right, I missed that. Added some quotes from the spec. – Sweeper May 22 '18 at 12:23
  • As a sidenote, if in an interview someone asks you the pitfall question "does the .NET implements an unified type system, where every type derives from object" the response is *no*. Pointers (`int*`) don't derive from `object` (for this reason you can't make a `List`), the same for managed references (`ref int`). See for example `typeof(int).MakePointerType().BaseType` vs `typeof(int).MakeByRefType()` vs `typeof(int)`) – xanatos May 22 '18 at 12:27
3

Arrays are a special case in .NET, because you are not allowed to directly inherit from the Array class.

From the documentation:

Single-dimensional arrays implement the IList<T>, ICollection<T>, IEnumerable<T>, IReadOnlyList<T> and IReadOnlyCollection<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.

This is due to the fact that generics did not exist in .NET 1.0, and to prevent breaking changes, a compiler hack had to be applied.

Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • Why would changing the Array class so that it implements the generic collections be a breaking change? – David Klempfner Dec 06 '19 at 01:36
  • If you can't write a class that derives from Array, then there are no classes that developers have written that would need to be updated to implement the methods in the generic collection classes. – David Klempfner Dec 06 '19 at 05:49
0

IEnumerable is an Interface and what you're referring to is Polymorphism.

Arrays, Lists, Collections, and many other types in .NET have a base IEnumerable interface at a minimum. If you make the parameter request Job[] then only an array of Job could be used, meaning a List or other collection would have to be converted to an Array before it could be passed to the parameter. This means the method, hopefully is dealing with and expecting the array for a specific reason. If the method doesn't care about the type of collection, list, or array and simply wants to iterate through the items, then it should look lower in the inheritance tree so that many types can use the method. Making the method IEnumerable<Job> allows the method to work with ANY type that derives from IEnumerable<T> where, in this case, T is of type Job.

Knowing this a List<Job>, ObservableCollection<Job>, Job[] or linq query with select of Job plus many more can use this method.

Michael Puckett II
  • 6,586
  • 5
  • 26
  • 46