Notice: "Possible Multiple enumeration of Ienumerable"

Asked

Viewed 576 times

8

I was doing some operations where I use collections. In one of these I needed to take a break (range) of numbers and I 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 do convert the variable range to a list the warning some.

What is Resharper’s reason for showing this warning and what he means?

  • 1

    I’m leaving but the answer seems to be here http://stackoverflow.com/q/8240844/221800

  • Enumerable.Rage returns which object? It is a Line in the BD?

  • No, he returns a IEnumerable<T>.

2 answers

5


The reason is that, when mentioning range or any method of extending it, you will be calling GetEnumerator() and iterating somehow on it.

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

Let’s go deep into the pain. Imagine this:

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

By assigning the variable, you have already created an iterable enumeration for 100000 records. By calling:

var primeiro = range.First();

You’re calling GetEnumerator() again, for an enumeration is not a concrete list. So much so that this gives a compilation 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();
    }
}

Imagine now 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 come true. He doesn’t know what’s behind it, but assumes the worst case ever.

2

The problem with Enumerable.Range, is that every time you have some iteration this code will be called and the query executed.

If you convert to list, after the first run the result will be curled 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 any query, the query will be rotated 2 times and so on...

Doing through a list, the variable "range" would only be executed once.

Source: https://helloacm.com/c-linq-possible-multiple-enumeration-of-ienumerable-resharper/

  • You mean by doing range.Count() the interval will be generated again to do the Count()?

  • Exactly, so the ideal is to convert to list.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.