I answered a question on Stack Overflow a couple of days ago and it sparked memories of several years ago when I was new to the industry. Something that confused me a little when starting out was around the use of interfaces. All of a sudden they started popping up in mass quantity as I started working on projects of significant size.
I wish someone had explained this to me back then. When deciding the parameters and return types of your methods, the parameters should be as abstract as possible and your return type should be as concrete as possible. The reason for this is to enable the most flexibility in your application.
Consider the example given in the SO question,
Returning a concrete
List<T> that implements
IList<T> only gives the method consumer more information. Given the definition of of
[SerializableAttribute] public class List<T> : IList<T>, ICollection<T>, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable
Returning as a
List<T> gives us the ability to call members on all of these interfaces in addition to on
List<T> itself. For example we could only use
List.BinarySearch(T) on a
List<T>, as it exists in
List<T> but not in
Likewise with parameters, the more abstract they are the more types can be passed in. If we only need to look through a collection of data in no particular order we should use the
IEnumerable<T> as the parameter type instead of a regular
List<T> This allows much more flexibility when consuming the method, we could pass in a
List<T> or a
SortedSet<T> or a
HashSet<T> etc. as they all implement the
In general to maximize the flexibility of our methods, we should take the most abstract types as parameters (only the things we’re going to use) and return the least abstract type possible (to allow a more functional return object).