This is an extremely useful thing.
Take any of the LINQ extension methods , for example. They don't care what is passed to them while it implements IEnumerable<T> . The idea is that they can all be applied to anything you can list using the foreach .
Imagine how pointlessly restrictive it would be if they all required you to pass arrays of T[] or List<T> , for example.
Here is just one very trivial illustration. Suppose LINQ extensions do not exist (which is actually a real possibility if I use .NET 2.0), and I want to write a Sum method.
I could write it like this:
public static double Sum(List<double> values) { double sum = 0.0; foreach (double value in values) { sum += value; } return sum; }
This is good and good, but pay attention to something here: I wrote a method to take a List<double> , which is a class with much more functionality than this code depends on . Where does he use Insert ? Where does he use RemoveAt ? FindAll ? Sort ? No, all this is not required. So what is really needed for this method to go through List<double> ?
Also, let's say I have double[] . Theoretically, I would have to use this parameter as the values parameter, since everything I do lists it with foreach ; but since I typed values like List<double> to pass the double[] method to my Sum , I would have to do this:
double sum = Sum(new List<double>(myArray));
This is just a completely unnecessary new object that I built, just to invoke the code that really had to process my original object.
By writing methods that take interfaces as parameters, you make your code more flexible and more powerful, and you avoid imposing inappropriate restrictions (give me X, although I could just as easily do this with Y) when invoking the code.