Warning: "Possible multiple enumeration of IEnumerable"

7

I was doing some operations where I make use of collections. In one of these I needed to get a range (% w / o%) of numbers and did the following:

var range = Enumerable.Range(0, 4); 

And then I tried to do something like

var primeiro = range.First();

However, Resharper keeps giving me the warning

  

Possible multiple enumeration of IEnumerable

If I convert the variable range to a list the warning some.

What is Resharper's reason for showing this warning and what does it mean?

    
asked by anonymous 25.11.2015 / 12:55

2 answers

4

The reason is that by mentioning range or any extension method of it, you are calling GetEnumerator() and iterating in some way about it.

For small lists like this, there is not much difference in performance. The thing changes with an enumeration of thousands of records.

Let's get down to the pain. Imagine the following:

var range = Enumerable.Range(0, 100000);

When you assign the variable, you have already created an iterable enumeration per 100000 records. When calling:

var primeiro = range.First();

You are calling GetEnumerator() again because an enumeration is not a concrete list. So much so that this gives a compile error:

public List<MeuObjeto>() 
{
    for (int i = 0; i < 10; i++) {
        yield return MeuObjeto();
    }
}

And this works:

public IEnumerable<MeuObjeto>() 
{
    for (int i = 0; i < 10; i++) {
        yield return MeuObjeto();
    }
}

Now imagine the cost of this last function over 100000 records. And that in your case, it runs 2 times.

That's why ReSharper suggests you make the list. He does not know what he's got behind, but he supposes the worst case ever.

    
25.11.2015 / 19:42
2

The problem with Enumerable.Range is that every time it has any iteration this code will be called and the query executed.

If you convert to list, after the first run the result will be cached in memory and then the rest will be computed on top of it.

In your case, if you do for example:

var range = Enumerable.Range(0, 4); 
var soma = range.Sum();
var itens = range.Count();

The range variable will be generated / executed 2 times, if you have a query, the query will be run 2 times and so on ...

By doing this through a list, the variable "range" would only be executed once.

Source: link

    
25.11.2015 / 13:36