Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IEnumerable<> vs List<> as a parameter [duplicate]

Tags:

In general I tend to use IEnumerable<> as the type when I pass in parameters. However according to BenchmarkDotNet:

[Benchmark] public void EnumeratingCollectionsBad() {     var list = new List<string>();     for (int i = 0; i < 1000; i++)     {         Bad(list);     } }  [Benchmark] public void EnumeratingCollectionsFixed() {     var list = new List<string>();     for (int i = 0; i < 1000; i++)     {         Fixed(list);     } }  private static void Bad(IEnumerable<string> list) {     foreach (var item in list)     {     } }  private static void Fixed(List<string> list) {     foreach (var item in list)     {     } } 
Method Job Runtime Mean Error StdDev Median Gen 0 Gen 1 Gen 2 Allocated
EnumeratingCollectionsBad .NET Core 3.1 .NET Core 3.1 17.802 us 0.3670 us 1.0764 us 17.338 us 6.3782 - - 40032 B
EnumeratingCollectionsFixed .NET Core 3.1 .NET Core 3.1 5.015 us 0.1003 us 0.2535 us 4.860 us - - - 32 B

Why would the interface version be so much slower (and memory intensive) than the concrete version?

like image 569
Murdock Avatar asked Jan 04 '21 21:01

Murdock


People also ask

What is the difference between an IEnumerable and a List?

IEnumerable is a deferred execution while List is an immediate execution. IEnumerable will not execute the query until you enumerate over the data, whereas List will execute the query as soon as it's called. Deferred execution makes IEnumerable faster because it only gets the data when needed.

What is IEnumerable <>?

IEnumerable is an interface defining a single method GetEnumerator() that returns an IEnumerator interface. It is the base interface for all non-generic collections that can be enumerated. This works for read-only access to a collection that implements that IEnumerable can be used with a foreach statement.

Why we use IEnumerable instead of List?

IEnumerable is best to query data from in-memory collections like List, Array etc. IEnumerable doesn't support add or remove items from the list. Using IEnumerable we can find out the no of elements in the collection after iterating the collection. IEnumerable supports deferred execution.

Should I pass IEnumerable or List?

If your method needs to accept a collection as a parameter, then generally IEnumerable<T> is the best choice. This offers the most flexibility to the caller. It doesn't matter what concrete collection type they use, and it even allows them to pass lazily evaluated sequences in.


1 Answers

Why would the interface version be so much slower (and memory intensive) than the concrete version?

When it uses the interface, the iteration has to allocate an object on the heap... whereas List<T>.GetEnumerator() returns a List<T>.Enumerator, which is a struct, and doesn't require any additional allocation. List<T>.Enumerator implements IEnumerator<T>, but because the compiler knows about the concrete type directly, it doesn't need to be boxed.

So even though both methods are operating on an object of the same type (a List<T>) one calls this method:

IEnumerator<T> GetEnumerator() 

... and one calls this:

List<T>.Enumerator GetEnumerator() 

The first almost certainly just delegates to the second, but has to box the result because IEnumerator<T> is a reference type.

The fact that List<T>.GetEnumerator() returns a mutable struct can have some surprising consequences but it's designed precisely to have the performance benefit you're seeing here.

The use of an interface vs a concrete type can itself have some very minor performance penalties, but the primary cause here is the difference in allocation.

like image 167
Jon Skeet Avatar answered Sep 18 '22 07:09

Jon Skeet