20

Disclaimer: I understand the difference between IEnumerable<T> and IEnumerator<T> and how to use both. This is not a duplicate of this or this.

This is more of a design question - since IEnumerator<T> already encapsulates all the necessary information (.Current, .MoveNext()) about something that can be enumerated, then what's the point of introducing a type (IEnumerable<T>) whose sole purpose is to return an instance of the former?

To be specific:

  1. Why can't foreach be designed to iterate directly through an IEnumerator<T>, like so:

    // foreach (var e in anEnumerator) { //... }
    while (anEnumerator.MoveNext())
    {
        doSomething(anEnumerator.Current);
    }
    
  2. Why can't Linq be built based directly off of IEnumerator<T>?

Community
  • 1
  • 1
KFL
  • 17,162
  • 17
  • 65
  • 89
  • 1
    It certainly *could* have been, but without talking to the .NET design team, I doubt you will get much of an answer here. – BradleyDotNET Sep 22 '14 at 22:34
  • 2
    There will presumably be other situations (beyond `foreach` loops) where an interface that promises "capable of providing an enumerator" is necessary. – Oliver Charlesworth Sep 22 '14 at 22:35
  • 1
    @BradleyDotNET It's been designed like so doesn't mean there isn't a reason behind. For everybody's benefit of learning something that potentially have a reason, I DON'T agree this should be closed. – KFL Sep 22 '14 at 22:36
  • 11
    It doesn't make sense: A `List` is *enumerable*, it's not an *enumerator*. A list shouldn't have to keep track of its "current" element in the context of however many clients are enumerating it. – Blorgbeard Sep 22 '14 at 22:37
  • I'd say IEnumerable acts like Func meaning not a live enumerator but the way to obtain it. But Func is not an interface, correct? – abatishchev Sep 22 '14 at 22:38
  • @KFL I'm sure there *is* a reason behind it, its just the SO community (with the notable exception of Eric Lippert) doesn't know the answer. It is inherently *opinion-based*. – BradleyDotNET Sep 22 '14 at 22:39
  • 8
    @BradleyDotNET While we may not be able to provide the exact thinking behind this decision at the time, the effects of the decision and benefits provided are very easy to explain. – Reed Copsey Sep 22 '14 at 22:43
  • @ReedCopsey I agree (and upvoted your excellent answer). Perhaps the question just need to be phrased differently. Either way, it has a great (objective) answer, and it should benefit the community as a whole. Everybody wins, and I'm happy with that :) – BradleyDotNET Sep 22 '14 at 22:49
  • 1
    How would you implement `from x in someList from y in someList select new {x, y}` to enumerate the *Cartesian product of a list with itself* in your proposed scheme? – Eric Lippert Sep 23 '14 at 02:03
  • Other than the other two questions aren't tagged as answered, how *is* this question not a duplicate? The answer simply explains the differences. – Peter Ritchie Sep 24 '14 at 16:19

1 Answers1

57

The two interfaces each represent very different concepts. IEnumerable<T> is something that "allows enumeration", where IEnumerator<T> is the representation of the enumeration itself.

If you were to merge these together, it would be impossible to enumerate a single collection more than once at the same time (without some other mechanism in place). For example, two threads doing a foreach over an array would no longer work, where that is perfectly acceptable in the current design.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • 10
    +1. You don't even have to involve threading: nested enumerations over the same collection also wouldn't work. – Blorgbeard Sep 22 '14 at 22:42
  • 1
    Conceptually, the two concepts are both conceptions. – crthompson Sep 22 '14 at 23:37
  • 24
    Short answer is that `IEnumerable` represents a [factory](http://en.wikipedia.org/wiki/Factory_%28object-oriented_programming%29) for `IEnumeration` instances. – Jeffrey Hantin Sep 23 '14 at 00:29
  • 1
    Also worth mentioning that the current design allows different kinds of enumerators for the same enumerable, i.e. reverse enumators. – Lorentz Vedeler Sep 24 '14 at 19:54
  • @LorentzVedeler How do you get that different kinds? IEnumerable have only one method without params. – tower120 Jan 12 '16 at 19:51
  • @tower120 if you have an implementation of IEnumerable, you could have a field with the IEnumerator and a method Reverse() which changes the field to a new ReverseEnumerator and then when the GetEnumerator-method is called, you would return tha instead of the regular IEnumerator-implementation. – Lorentz Vedeler Jan 13 '16 at 09:23
  • @LorentzVedeler - Yes, indeed. But this would be very unclear. You would "never" know in which way you go next call :)) – tower120 Jan 13 '16 at 10:26