Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IList, ICollection or IEnumerable in service interface?

Tags:

c#

asp.net-mvc

I'm building a service for accessing my database with Entity Framework in ASP.NET MVC 5. So I'm writing first a base service with his interface. But I'm worry about a little thing.

Usually I return an IEnumerable<T> in my interface, but that often leads to ToList() calls in the code.

So I was wondering what is the best to return in such an interface. I could just return IList but I'm afraid that it may be too much and that I won't need all of the methods provided with IList.

Here's my code :

public interface IBaseService<T>
{
    T Add(T obj);
    T Update(T obj);
    T Remove(string id);
    T Get(string id);

    ICollection<T> Find(Expression<Func<bool, T>> func);
    ICollection<T> GetAll();
}
like image 701
Antoine Thiry Avatar asked Apr 04 '17 08:04

Antoine Thiry


People also ask

Should I use ICollection or IEnumerable?

IEnumerable contains only GetEnumerator() method, like read-only iterate. ICollection is one step ahead of IEnumerable. If we want some more functionality like Add or remove element, then it is better to go with ICollection because we cannot achieve that with IEnumerable. ICollection extends IEnumerable.

What is difference between IEnumerable and IList?

IList doesn't support further filtering. IEnumerable exists in System. Collections Namespace. IEnumerable is a forward only collection, it can't move backward and between the items.

What is the difference between ICollection and IList?

ICollection<T> is an interface that exposes collection semantics such as Add() , Remove() , and Count . Collection<T> is a concrete implementation of the ICollection<T> interface. IList<T> is essentially an ICollection<T> with random order-based access.

What is the use of IEnumerable ICollection IList and IDictionary?

To begin with, all the interfaces (ICollection, IList, IQueryable, IDictionary) inherit from IEnumerable, which allows us to use the foreach statement.


3 Answers

You said that

Usually I return an IEnumerable in my interface, but that often leads to ToList() calls in the code.

You have to find out why you are calling ToList() on the results. It's possible, but unlikely, that you want to modify the result (add\remove items). It's generally not a good practice to return modifiable collection from methods like Find or GetAll, but you can return ICollection<T> or IList<T> (if you also need fast access via indexer or to insert\remove at specific positions).

However much more likely that you call to ToList to figure out how many elements are there and\or to access specific elements. If you need just Count - return IReadOnlyCollection<T> which extends IEnumerable<T> with just Count property. If you also need fast access via indexer - return IReadOnlyList<T> which extends IReadOnlyCollection<T> with indexer.

Both Array and List<T> implement all those interfaces so you can just return those classes as is:

 static IReadOnlyList<string> Test() {
      return new string[0]; // fine
 }

However, when returning List this way - caller might cast it back to IList<T> and still modify it. That's not a problem usually, but if you want to prevent that, use AsReadOnly on list (it will not copy anything to the new list so don't worry about perfomance):

static IReadOnlyList<string> Test() {
      return new List<string>().AsReadOnly(); // not required but good practice
 }
like image 55
Evk Avatar answered Nov 15 '22 07:11

Evk


It depends on your intention. In most cases your return type should probably be IReadOnlyCollection<T>. In rare cases where you want the caller to be able to modify the collection, you can return ICollection<T>. Use IEnumerable<T> only if you are certain that the caller will only require forward iteration.

like image 38
Erik Molekamp Avatar answered Nov 15 '22 07:11

Erik Molekamp


I guess the purest solution would be to go with IEnumerable<T>, but it comes down to setting a convention in your solution. If you're responsible for architecture, you might as well decide to return List<T> just to have the comfort of broader set of methods at hand.

like image 35
borkovski Avatar answered Nov 15 '22 06:11

borkovski