Recently I have been researching some conventions in writing functions that return a collection. I was wondering whether the function that actually uses a List<int> should return a List<int> or rather IList<int>, ICollection<int> or IEnumerable<int>. I created some tests for performance and I was quite surprised with the results.
static List<int> list = MakeList();
static IList<int> iList = MakeList();
static ICollection<int> iCollection = MakeList();
static IEnumerable<int> iEnumerable = MakeList();
public static TimeSpan Measure(Action f)
{
    var stopWatch = new Stopwatch();
    stopWatch.Start();
    f();
    stopWatch.Stop();
    return stopWatch.Elapsed;
}
public static List<int> MakeList()
{
    var list = new List<int>();
    for (int i = 0; i < 100; ++i)
    {
        list.Add(i);
    }
    return list;
}
public static void Main()
{
    var time1 = Measure(() => { // Measure time of enumerating List<int>
        for (int i = 1000000; i > 0; i-- ) {
            foreach (var item in list)
            {
                var x = item;
            }
        }
    });
    Console.WriteLine($"List<int> time: {time1}");
    var time2 = Measure(() => { // IList<int>
        for (int i = 1000000; i > 0; i-- ) {
            foreach (var item in iList)
            {
                var x = item;
            }
        }
    });
    Console.WriteLine($"IList<int> time: {time2}");
    var time3 = Measure(() => { // ICollection<int>
        for (int i = 1000000; i > 0; i-- ) {
            foreach (var item in iCollection)
            {
                var x = item;
            }
        }
    });
    Console.WriteLine($"ICollection<int> time: {time3}");
    var time4 = Measure(() => { // IEnumerable<int>
        for (int i = 1000000; i > 0; i-- ) {
            foreach (var item in iEnumerable)
            {
                var x = item;
            }
        }
    });
    Console.WriteLine($"IEnumerable<int> time: {time4}");
}
Output:
List<int> time: 00:00:00.7976577
IList<int> time: 00:00:01.5599382
ICollection<int> time: 00:00:01.7323919
IEnumerable<int> time: 00:00:01.6075277
I've tried different order of the measures or making the MakeList() return one of the above interfaces but all of it only confirms that returning a List<int> and processing it as a List<int> is about twice as fast as with the interfaces.
However various sources, including this answer claim that you should never return List<> and always use an interface.
So my question is:
- Why is processing a List<int>about twice as fast as the interfaces?
- What should we return from a function and how to manage the code if we care about performance?
 
    