166

I only watched a few webcasts before I went head first in to designing a few Entity Framework applications. I really didn't read that much documentation and I feel like I am suffering for it now.

I have been using List<T> in my classes, and it has worked great.

Now I have read some documentation and it states that I should have been using ICollection<T>. I changed to this, and it didn't even cause a model context change. Is this because both List<T> and ICollection<T> inherit IEnumerable<T>, and that is what is actually required for EF?

However, if this is the case, why doesn't the EF documentation state that it requires IEnumerable<T> instead of ICollection<T>?

TylerH
  • 20,799
  • 66
  • 75
  • 101
wil
  • 2,019
  • 2
  • 15
  • 14
  • There is a recent [2015] CodeProject article which explains the difference in much detail and graphical representation with **sample code**. It is not focused directly at EF but still hope it will be of greater help: [List vs IEnumerable vs IQueryable vs ICollection vs IDictionary](http://www.codeproject.com/Articles/832189/List-vs-IEnumerable-vs-IQueryable-vs-ICollection-v) – BiLaL May 23 '15 at 18:16

3 Answers3

169

Entity Framework would use ICollection<T> because it needs to support Add operations, which are not part of the IEnumerable<T> interface.

Also note that you were using ICollection<T>, you were merely exposing it as the List<T> implementation. List<T> brings along with it IList<T>, ICollection<T>, and IEnumerable<T>.

As for your change, exposing via the interface is a good choice, despite List<T> working. The interface defines the contract but not the implementation. The implementation could change. In some instances, perhaps the implementation could be a HashSet<T>, for example. (This is a mindset you could use for more than just Entity Framework, by the way. A good object-oriented practice is to program towards the interface and not the implementation. Implementations can and will change.)

Anthony Pegram
  • 123,721
  • 27
  • 225
  • 246
  • 8
    So.... just for me to understand a bit further - List inherits IList, which inherits ICollection, which inherits IEnumerable? – wil Oct 05 '11 at 02:10
  • 6
    Yes, that's the chain. `List` has to implement each of those interfaces (`IList`, `ICollection`, `IEnumerable`) because of the inheritance hierarchy. For completion, `IList` also picks up the non-generic `IList`, `ICollection` and `IEnumerable` interfaces. – Anthony Pegram Oct 05 '11 at 02:17
  • Thank you... Some of the Ixxx features still escape my understanding! You have made sense, however, one last thing that is annoying me, if the other Ixx's inherit IEnumerable, how does it add to the IEnumerable if an Ienumerable is read only? ... If it is too complex, don't worry, when I have a bit of time, I will try to fire up reflector! – wil Oct 05 '11 at 13:55
  • 10
    Normal Linq operations do not add or mutate things, they simply filter, group, project, etc. Forward-only, read-only sequences are all that's necessary to support those operations. When you have a Linq provider such as Entity Framework that deals with data persistence, the ability to Add is a substantial benefit that requires a beefier interface, which is what invites `ICollection` to the party (and this interface brings along with it `IEnumerable`, so the "normal" Linq operations are still valid). – Anthony Pegram Oct 05 '11 at 13:59
  • @AnthonyPegram: I think it's strictly incorrect to say that all three interfaces must be implemented. Since IList inherits ICollection which inherits IEnumerable, it is sufficient for List to simply implement IList. – CJ7 Dec 17 '11 at 07:05
  • 1
    @CraigJ, depends on what you mean by implementation. List has to implement each interfaces' methods and properties. List does not have to *declare* it is implementing those interfaces (beyond just IList), as that fact is already transitively declared. – Anthony Pegram Dec 17 '11 at 14:59
  • I am a little late to the party for this convo, but with the inheritance of List, would it take more time for each one? Like would ICollection be faster to define? If that makes sense? – Christian4423 Sep 01 '17 at 18:02
80

They picked the interface they did because it gives a comprehensible abstraction over the magic queries the Entity Framework performs when you use Linq.

Here's the difference between the interfaces:

  • IEnumerable<T> is read-only
  • You can add and remove items to an ICollection<T>
  • You can do random access (by index) to a List<T>

Out of those, ICollection and IEnumerable map well to database operations, since querying and adding/removing entities are things you might do in a DB.

Random access by index doesn't map as well, since you'd have to have an existing query result to iterate over, or each random access would query the database again. Also, what would the index map to? Row number? There aren't a lot of row number queries you'd want to do, and it isn't useful at all in building up bigger queries. So they simply don't support it.

ICollection<T> is supported, and will allow you to both query and change data, so use that.

The reason List<T> works to begin with is because the EF implementation ends up returning one in the end. But that's at the end of your query chain, not at the beginning. So making your properties ICollection<T> will make it more obvious that the EF creates a bunch of SQL and only returns a List<T> at the end, rather than doing queries for each level of Linq that you use.

Merlyn Morgan-Graham
  • 58,163
  • 16
  • 128
  • 183
10

ICollection differs from IEnumerable in that you can actually add items to the collection, whereas with IEnumerable you can't. So in your POCO classes, for instance, you want to use ICollection if you intend to allow the collection to be added to. Make the ICollection virtual to benefit from lazy loading too.

Ralph Lavelle
  • 5,718
  • 4
  • 36
  • 46
  • 1
    I want to understand - you can do the same operations (and more!) with List. Why ICollection? Why not List? Looks simpler and more powerful. – monstro Oct 18 '15 at 17:30
  • 1
    List Implements ICollection and IEnumerable. More operation but with that comes more overhead. – IronAces Jan 25 '17 at 11:23