Linq优化内的一个foreach

biz*_*dee 5 c# linq optimization foreach

我一直在寻找一种将foreach循环分成多个部分的方法,并且遇到了以下代码:

foreach(var item in items.Skip(currentPage * itemsPerPage).Take(itemsPerPage))
{
    //Do stuff
}
Run Code Online (Sandbox Code Playgroud)

items.Skip(currentPage * itemsPerPage).Take(itemsPerPage)在每次迭代中处理,还是会被处理一次,并且编译器会自动使用foreach循环的临时结果?

Tig*_*ran 9

不,它会被处理一次.

它是一样的:

public IEnumerable<Something> GetData() {
    return someData; 
}


foreach(var d in GetData()) {
   //do something with [d]
}
Run Code Online (Sandbox Code Playgroud)


Ahm*_*IEM 6

foreach结构相当于:

IEnumerator enumerator = myCollection.GetEnumerator();
try
{
   while (enumerator.MoveNext())
   {
       object current = enumerator.Current;
       Console.WriteLine(current);
   }
}
finally
{
   IDisposable e = enumerator as IDisposable;
   if (e != null)
   {
       e.Dispose();
   }
}
Run Code Online (Sandbox Code Playgroud)

所以,不,myCollection只会被处理一次.

更新:

请注意,这依赖于执行IEnumeratorIEnumerable用途.

在这个(邪恶的)例子中:

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


namespace TestStack
{
    class EvilEnumerator<T> : IEnumerator<T> {

        private IEnumerable<T> enumerable;
        private int index = -1;

        public EvilEnumerator(IEnumerable<T> e) 
        {
            enumerable = e;
        }


        #region IEnumerator<T> Membres

        public T Current
        {
            get { return enumerable.ElementAt(index); }
        }

        #endregion

        #region IDisposable Membres

        public void Dispose()
        {

        }

        #endregion

        #region IEnumerator Membres

        object IEnumerator.Current
        {
            get { return enumerable.ElementAt(index); }
        }

        public bool MoveNext()
        {
            index++;
            if (index >= enumerable.Count())
                return false;
            return true;
        }

        public void Reset()
        {

        }

        #endregion
    }
    class DemoEnumerable<T> : IEnumerable<T>
    {

        private IEnumerable<T> enumerable;

        public DemoEnumerable(IEnumerable<T> e)
        {
            enumerable = e; 
        }


        #region IEnumerable<T> Membres

        public IEnumerator<T> GetEnumerator()
        {
            return new EvilEnumerator<T>(enumerable);
        }

        #endregion

        #region IEnumerable Membres

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion
    }

    class Program
    {
        static void Main(string[] args)
        {
            IEnumerable<int> numbers = Enumerable.Range(0,100);
            DemoEnumerable<int> enumerable = new DemoEnumerable<int>(numbers);
            foreach (var item in enumerable)
            {
                Console.WriteLine(item);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

每次迭代enumerable都会评估numbers两次.