Tuesday, September 6, 2011

List or IList: that is the question

On a day during a conversation at work, a question arises: Why do so many developers always refer to List<T> instead of IList<T> in C#? But a convincing answer to this question did not appear. Thus the principle to depend on abstractions and not on concrete implementations was being despised.


Apparently it was not the first time that this question appears. And it is possible to notice that most developers using List<T> instead of IList<T> had been Java programmers one day. Is this the reason?


In C# it is common to use the letter "I" at the beginning of interface names. People who have programmed in Java might be confused since List represents an interface (in Java) while LinkedList and Stack are examples of implementations. It is also important to note that in C#, LiskedList<T>, Queue<T> and Stack<T> do not implement IList<T>, because they do not provide access by index.


It became necessary to understand the generic class List<T>, and the interfaces that it implements (IEnumerable<t>, ICollection<T>, IList<T>, IEnumerable, ICollection and IList). Thus, such interfaces could be used as a reference instead of the concrete class.


With that understanding about interfaces in mind, it was necessary to make some refactoring in the code where List<T> was being used. At first, replacing at least the return of a method from IList<T> to IEnumerable<T>. With this change, some compilation errors appeared, the method Add(T) was missing. But with ICollection<T> the code worked normally. In some other cases the IEnumerable<T> met the need because it only had to scroll through the list of items returned.


Later, we found a situation that was necessary to access a specific item of the structure, which was solved using the IList<T> interface in the return. Then a AddRange(IEnumerable<T>) method of List<T> was being used, which could easily be replaced with an extension method for ICollection<T>.


But after all these the question number two came up: Were all operations being conducted in the correct place? Since the return of each method was more conscious, it was easier to notice that certain classes were doing more than they should.


At the end, the refactoring was successful, returns of all methods that were using List<T> have been replaced by an appropriate interface. With a little more research it was possible to notice that not only developers accustomed with the List interface in Java were referring to List<T> in C#, but many people use the reference to List<T> due to resources provided by the implementation. A method as AddRange(IEnumerable<T>) could be called anywhere. A tempting proposal. However, relying on abstractions makes the code to become more flexible. And relying on interfaces that only contains the necessary functionality, limited to not try to do in a class which should not be her responsibility.

1 comment: