3

I am trying to understand the IEnumerable interface in C#. As it is stated in MSDN
IEnumerable exposes an enumerator, which supports a simple iteration over a non-generic collection. This is quite simple. When we have a collection that implements this interface then, we get an enumerator, which implements the IEnumerator interface, (http://msdn.microsoft.com/en-us/library/system.collections.ienumerable.getenumerator(v=vs.110).aspx), and the using this enumerator we can iterate through all the elements of the collection in a way like the below:

foreach(var item in items)
{
    // code goes here
}

In the above snippet of code, items is a collection that implements the IEnumerable interface. This is possible because the enumerator has a property called Current, which has the current element of the collection and a method MoveNext, which is used by the enumerator, to move to the next element. Last but not least, it has a method called Reset, which sets the enumerator to its initial position, which is before the first element in the collection, as it is stated in MSDN.

Let we have the following snippet of code:

int[] array = new int[10] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
IEnumerable<int> numbers = array;
foreach (var number in numbers)
{
    Console.WriteLine(number);
}

In the above snippet of code we initialize an array of integers and then we define a type of IEnumerable that points to the array. Since numbers implements the IEnumerable, we can iterate through it's elements using the above foreach.

I think that the compiler behind the scenes emits some code, when we define the numbers and then try to iterate through it's elements. Actually I found that Array implements IEnumerable<T>.

My question is every time we define an array, since an array is an object that implements IEnumerable and IEnumerator, the corresponding methods are implemented by the compiler?

Thanks in advance for any help !

Christos
  • 53,228
  • 8
  • 76
  • 108
  • 2
    They are implemented already (since `Array` implements `IEnumerable` as you yourself noted), and `foreach` is nothing but syntax sugar that actually calls enumerator methods, see http://stackoverflow.com/questions/5816776/in-c-is-foreach-purely-a-syntactic-sugar-or-is-there-anything-deeper-about – Konrad Morawski Dec 12 '13 at 12:11
  • 1
    A good writeup on this topic [here](http://csharpindepth.com/articles/chapter6/iteratorblockimplementation.aspx) – JMK Dec 12 '13 at 12:12
  • 2
    They are actually added at runtime by the CLI, see 'important' note here: http://msdn.microsoft.com/en-us/library/system.array.aspx – Baldrick Dec 12 '13 at 12:13
  • 1
    Syntactic sugar is the key here - the same thing that generates a `PropertyName_set` and `PropertyName_get` when you create a `string PropertyName { get; set;}`. .NET just abstracts away this implementation detail so that the code is easier to work with and nicer to read. You have the same methodology for properties in Java, but unlike .NET in order to get/set them you have to explicitly call the getter/setter methods. This is the same kind of thing that's happening in your `foreach` loop - the actual generated code calls the enumerator, but you don't see that because VS is being helpful! – Charleh Dec 12 '13 at 12:15
  • 1
    And if you look at the implementation of an enumerator (there's a good example on the link JMK provided) you can see why it's a good thing that .NET generates it! – Charleh Dec 12 '13 at 12:19
  • @Charleh: It's not syntactic sugar. If `T` inherits from `U`, then `T[]` inherits from `U[]`, and thus `T[]` will not only implement `IList`, but also `IList`. If something is syntactic sugar, that implies the compiler is responsible for it, but there is no way a compiler could generate code fro a generic type which implements a non-covariant interface (e.g. `List`) covariantly the way arrays do. – supercat Dec 12 '13 at 15:52
  • I'm talking about the foreach, not the implementation of the interface - probably should have made it clear – Charleh Dec 12 '13 at 16:27

1 Answers1

2

Your question,

My question is every time we define an array, since an array is an object that implements IEnumerable and IEnumerator, the corresponding methods are implemented by the compiler?

As per the MSDN documentation under Remarks section it is clearly mentioned,

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 therefore are not visible to the documentation build tools. As a result, the generic interfaces do not appear in the declaration syntax for the Array class, and there are no reference topics for interface members that are accessible only by casting an array to the generic interface type (explicit interface implementations). The key thing to be aware of when you cast an array to one of these interfaces is that members which add, insert, or remove elements throw NotSupportedException.

Yes, the implementation are provided to arrays at run time by the compiler.

EDIT Your question in comment

That happens with all the non-generic collections?

After reading the posts,

and after looking at all the Collections, I found that ArrayList, BitArray etc all are collections but do not implement any of generic interfaces.

Correct me if I am wrong at this I don't think so that implementation of all the Collection will be provided at run time.

Community
  • 1
  • 1
Deepak Bhatia
  • 6,230
  • 2
  • 24
  • 58
  • That happens with all the non-generic collections? – Christos Dec 12 '13 at 14:23
  • @ChristosPaisios I am unable to understand what you actually mean by `That happens with all the non-generic collections` are you asking or commenting – Deepak Bhatia Dec 12 '13 at 14:56
  • 2
    Another thing to be aware of, which the note does not mention, is that a `Cat[]` may be cast to `IList`, but the implementation would provide no method for checking whether a given `Animal` can be stored by index into the collection, except by either (1) determining that `IList` is actually an array, and checking whether the item being stored will fit therein, or (2) attempting to store the item and seeing if it throws an exception. – supercat Dec 12 '13 at 15:55