Difference between IEnumerable and IEnumerable<T>?
Asked Answered
L

4

64

What is the difference between IEnumerable and IEnumerable<T>?

I've seen many framework classes implementing both these interfaces, therefore I would like to know what advantages one get by implementing both?

Please have a look how they've been defined:

public interface IEnumerable
{
    [DispId(-4)]
    IEnumerator GetEnumerator();
}
public interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> GetEnumerator();
}

As we see, IEnumerable<T> derives from IEnumerable, that means whatever IEnumerable has, IEnumerable<T> inherits, then why do we implement both instead of just IEnumerable<T>? Is implementing IEnumerable<T> not enough?

Likewise, there are other similar pairs:

  • IList and IList<T>
  • ICollection and ICollection<T>

I would like to know about these as well.

Laundress answered 11/2, 2011 at 17:33 Comment(0)
P
72

Basically the nongeneric interfaces came first, in .NET 1.0 and 1.1. Then when .NET 2.0 came out, the generic equivalents came out. Life would have been a lot simpler if generics had made it into .NET 1.0 :)

In terms of implementing "only" IEnumerable<T> instead of both - you basically have to implement both, and you have to use explicit interface implementation too, given that both define a parameterless GetEnumerator method. As IEnumerator<T> extends IEnumerator too, it's normally something like this:

public IEnumerator<T> GetEnumerator()
{
    // Return real iterator
}

// Explicit implementation of nongeneric interface
IEnumerator IEnumerable.GetEnumerator()
{
    // Delegate to the generic implementation
    return GetEnumerator();
}

On the other hand, with the iterator blocks introduced in C# 2 (with yield return etc) you rarely need to implement these things entirely by hand, fortunately. You may need to write something like the above, and then use yield return in the GetEnumerator method.

Note that IList<T> does not extend IList, and ICollection<T> does not extend ICollection. That's because it's less type-safe to do so... whereas any generic iterator can be seen as a nongeneric iterator due to the (potentially boxing) conversion of any value to object, IList and ICollection allow values to be added to the collection; and it doesn't make sense to add (say) a string to an IList<int>.

EDIT: The reason why we need IEnumerable<T> is so that we can iterate in a type-safe way, and propagate that information around. If I return an IEnumerable<string> to you, you know that you can safely assume everything returned from it will be a string reference or null. With IEnumerable, we had to effectively cast (often implicitly in a foreach statement) each element that was returned from the sequence, because the Current property of IEnumerator is just of type object. As for why we still need IEnumerable - because old interfaces never go away, basically. There's too much existing code using it.

It would have been possible for IEnumerable<T> not to extend IEnumerable, but then any code wanting to make use of an IEnumerable<T> couldn't call into a method accepting IEnumerable - and there were a lot of methods like that from .NET 1.1 and 1.0.

Prognathous answered 11/2, 2011 at 17:34 Comment(6)
@Jon: the question is: why do we even need to implement IEnumerable when we already implement IEnumerable<T>, or vice-versa?Laundress
@Nawaz: I've edited my answer. How comfortable are you with the idea of why generics are a good thing?Prognathous
@Jon: The edit is good. thanks. Now what I understand is that IEnumerable is there for backward compatibility, right?Laundress
@Nawaz: Mostly. Basically there's a lot of code using it - you can't really remove a public interface after you've released it.Prognathous
Jon you really are a truly amazing c# guru, keep up the good work! This helped alot!Clock
@RoyiNamir: It's unclear why you're asking this as a comment on this answer. If you have a separate question, please ask it as a separate question.Prognathous
U
11

One returns an object of type Object, the other returns an object of type T.

Undersigned answered 11/2, 2011 at 17:34 Comment(0)
U
3

As to why you see classes defining both, enough though IEnumerable< T > implements IEnumerable, its not needed but is is nice in a self documenting to list the sub interfaces at times. Consider

interface IA { }
interface IB : IA { }

class A : IB {} // legal, IB implements IA

class B : IA, IB {} // also legal, possible more clear on intent
Unreal answered 11/2, 2011 at 17:40 Comment(0)
L
-1

While iterating through the loop IEnumerator maintains the state. It remembers the cursor position and IEnumerable does not.

Lengel answered 24/2, 2013 at 22:55 Comment(1)
That was not the question.Watersoak

© 2022 - 2024 — McMap. All rights reserved.