4

I have the following class that doesn't implement IEnumerable but is working perfectly with foreach. And also, arrays are working without implementing IEnumerable.

So why does it keep saying that IEnumerable needs to be implemented in collections to use with foreach. I'm confused, please assist me.

class Parent
    {
        public int MyProperty { get; set; }
        public void GetData()
        {
            Console.WriteLine("parent");
        }
    }



Parent[] p = new Parent[3]
    {
        new Parent(){MyProperty=90},
        new Parent(){MyProperty=50},
        new Parent(){MyProperty=100}
    };


foreach (var item in p)
    {
        Parent it = item;
        Console.WriteLine(it.MyProperty);
    }
  • @MasonWheeler corrected – Roshan Fernando Jun 25 '16 at 17:11
  • 6
    @RoshanFernando: p is an array in your example, and arrays does implement IEnumerable. – JacquesB Jun 25 '16 at 17:32
  • @DavidPacker Thanks. could you please elaborate your answer by providing a simple example. items in P means properties or what – Roshan Fernando Jun 25 '16 at 17:41
  • 2
    @DavidPacker "You must implement the IEnumerable interface if you want to call foreach on your class directly." no, this is not true. Read my or MetaFight's answer – sara Jun 25 '16 at 17:50
  • 1
    @DavidPacker If you can use foreach without implementing the interface, then saying that you must implement the interface to use foreach is objectively false. This is basically akin to saying that you can only await Tasks or that you can only use LINQ queries with IEnumerable or IQueryable. Just because they are the most common doesn't mean that it has to be that way. – sara Jun 25 '16 at 18:01
13

The official documentation looks straightforward to me:

The foreach statement repeats a group of embedded statements for each element in an array or an object collection that implements the System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T> interface.

Note that kai's answer, backed by the C# Language Specification, shows that the documentation is too restrictive: it is not necessary to implement one of those interfaces in order to use a class with a foreach. Those are implementation details which are interesting by themselves, but irrelevant for your original question, since in your sample code, you're actually using an IEnumerable.

What happens is that the sequence you use is an array, and, according to the documentation, emphasis mine:

Array types are reference types derived from the abstract base type Array. Since this type implements IEnumerable and IEnumerable<T>, you can use foreach iteration on all arrays in C#.

Similarly, you could look at the definition of the Array class:

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

See the IEnumerable among the interfaces?

More interestingly, exploring the result of typeof(int[]) gives you this list for ImplementedInterfaces property:

  • typeof(ICloneable)
  • typeof(IList)
  • typeof(ICollection)
  • typeof(IEnumerable)
  • typeof(IStructuralComparable)
  • typeof(IStructuralEquatable)
  • typeof(IList<Int32>)
  • typeof(ICollection<Int32>)
  • typeof(IEnumerable<Int32>)
  • typeof(IReadOnlyList<Int32>)
  • typeof(IReadOnlyCollection<Int32>)

where you can see the additional generic interfaces as well. (This also explains why you can write IList<int> a = new[] { 1, 2, 3 };.)

Similarly, List<T>, ConcurrentQueue<T>, etc. implement IEnumerable and Enumerable<T>.

So when you say that:

And also , arrays are working without implementing IEnumerable.

this is simply not true. Arrays are implementing IEnumerable. As for:

I have following class that didnt implement IEnumerable but working perfectly with foreach.

it would be interesting to see the actual code (the one you have in your question uses an array). What is probably happening is that your class, without explicitly declaring IEnumerable or IEnumerable<T> among its interfaces, implements a more specific interface, such as ICollection<T>, which, in turn, inherits from IEnumerable:

public interface ICollection<T> : IEnumerable<T>, IEnumerable

And if not, well, you are probably in the case illustrated in kai's answer.

  • Please check my code sample above. it is working without IEnumerable – Roshan Fernando Jun 25 '16 at 17:13
  • Thanks yes it s array. Then it is correct. But how we will create a collection without array. (without BCL classes most of them implemented ienumarable) – Roshan Fernando Jun 25 '16 at 17:20
  • "how we will create a collection without array": which one? There are dozens of different sequence-based data structures in .NET. Depending on your actual needs, you may do new List<int>(), or new HashSet<string>(), or new Queue<long>(), or new Dictionary<string, string>()... – Arseni Mourzenko Jun 25 '16 at 17:26
  • Sorry, i m asking when we need to explicitly implement iIEnumerable because the collections are most of the time arrays or they are already implemented IEnumerable . Can you provide a simple example where we need to implement IEnumerable to iterate. – Roshan Fernando Jun 25 '16 at 17:29
  • @RoshanFernando: when you are creating your own data structure which represents a sequence, such as a linked list (since .NET's LinkedList<T> is actually a doubly-linked list). – Arseni Mourzenko Jun 25 '16 at 17:33
8

It isn't required. The foreach keyword basically just "rewrites" your code so it becomes a while loop calling MoveNext() and looking at Current, but the interface IEnumerable isn't needed. This is backed up by the C# Language Specification under section 15.8.4 The foreach statement

Try compiling the following code and you'll see msbuild has nothing to say about it:

public class Foo<T>
{
    public Foo(T value)
    {
        Value = value;
    }

    public T Value { get; }

    public FooEnumerator<T> GetEnumerator()
    {
        return new FooEnumerator<T>(Value);
    }
}

public class FooEnumerator<T>
{
    private bool _hasValue = true;
    private readonly T _value;

    public FooEnumerator(T value)
    {
        _value = value;
    }

    public bool MoveNext()
    {
        if (_hasValue)
        {
            Current = _value;
            return true;
        }
        else
        {
            _hasValue = false;
            return _hasValue;
        }
    }

    public T Current { get; private set; }
}

public class Test
{
    public static void Run()
    {
        foreach (var x in new Foo<int>(1))
        {
            Console.WriteLine(x);
        }
    }
}

All that is required to use the foreach keyword is that there is a method called GetEnumerator() that returns ANY type that has a method called MoveNext() returning a bool and a property called Current (of any type) with at least a visible getter

It works similarly to LINQ query comprehensions. The following code compiles and runs smoothly:

public class Foo<T>
{
    public Foo(T value)
    {
        Value = value;
    }

    public T Value { get; }

    public Foo<U> Select<U>(Func<T, U> f)
    {
        return new Foo<U>(f(Value));
    }

    public Foo<U> SelectMany<U>(Func<T, Foo<U>> f)
    {
        return f(Value);
    }

    public Foo<V> SelectMany<U, V>(Func<T, Foo<U>> f, Func<T, U, V> g)
    {
        return new Foo<V>(g(Value, f(Value).Value));
    }
}

public class Test
{
    public static void Run()
    {
        var result =
            from x in new Foo<int>(5)
            from y in new Foo<int>(9)
            select (x + y).ToString();

        // result is now a Foo<string> containing the value "14"
    }
}
  • Thanks. But could you please answer my question usingthe sample provided. – Roshan Fernando Jun 25 '16 at 17:15
  • The official documentation says it is required. You tell the exact opposite. Can you provide some authoritative source for your claim? – Arseni Mourzenko Jun 25 '16 at 17:15
  • Added an example of Foo<T> being iterable using foreach without implementing IEnumerable – sara Jun 25 '16 at 17:24
  • 3
    @MainMa I think the C# compiler is a pretty good source. My code compiles and runs. You could probably look it up in the language spec also. – sara Jun 25 '16 at 17:25
  • "result is not a Foo<string>" my compiler VS2015 tells me that result is a Foo<string>. Please check it. – marbel82 Aug 30 '16 at 10:23
7

Eric Lippert actually has a piece about this:

https://blogs.msdn.microsoft.com/ericlippert/2011/06/30/following-the-pattern/

Eric's explanation:

What is required is that the type of the collection must have a public method called GetEnumerator, and that must return some type that has a public property getter called Current and a public method MoveNext that returns a bool.

Interestingly (and as the article goes on to mention) this is a relic of C# 1.0's lack of generics. The C# compiler used Duck typing to allow Enumerators to return the appropriate type for the collection instead of returning Object and incurring boxing/unboxing costs for value types.

I remember learning about this when I was still in university and learning C#. It made me feel icky at the time. Now I find it kind of clever!

  • 1
    I agree, I found it distasteful when I first saw it as well. But after having to actually deal with the realities of retrofitting new features into old languages with real-world libraries that have multiple inconsistent coding patterns, suddenly this sort of duck typing becomes really attractive. – Eric Lippert Jul 8 '16 at 15:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.