Why is Enumerable.Range repeated twice?

I know I'm IEnumerablelazy, but I don't understand why Enumerable.Rangeit repeats here twice:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication
{
    class Program
    {
        static int GetOne(int i)
        {
            return i / 2;
        }

        static IEnumerable<int> GetAll(int n)
        {
            var items = Enumerable.Range(0, n).Select((i) =>
            {
                Console.WriteLine("getting item: " + i);
                return GetOne(i);
            });

            var data = items.Select(item => item * 2);

            // data.Count does NOT causes another re-iteration 
            Console.WriteLine("first: items: " + data.Count());
            return data;
        }

        static void Main()
        {
            var data = GetAll(3);

            // data.Count DOES cause another re-iteration 
            Console.WriteLine("second: items: " + data.Count());
            Console.ReadLine();
        }
    }
}

Result:

getting item: 0
getting item: 1
getting item: 2
first: items: 3
getting item: 0
getting item: 1
getting item: 2
second: items: 3

Why doesn't he get a repeat in the "first" case, but does it in the second?

+4
source share
3 answers

You start a repeated iteration on Count(a full iteration of the source is required to provide a response). IEnumerablewill never save its values ​​and will always re-iterate when necessary.

, Array List<T>, , yield return (, Enumerable.Range), .

ReSharper , .

Count, . , , , - var myCachedValues = myEnumerable.ToArray(), ( ).

( ), , , - , . IRepeatable. , .

+5

Enumerable.Range ( ) , . Count, .

+2

Due to delayed execution, so if you want to execute only once, change the line

var data = items.Select(item => item * 2);

to

 var data = items.Select(item => item * 2).ToList();
+1
source

Source: https://habr.com/ru/post/1526715/


All Articles