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();
}
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.
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.
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.
To begin with, all the interfaces (ICollection, IList, IQueryable, IDictionary) inherit from IEnumerable, which allows us to use the foreach statement.
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
}
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With