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循环的临时结果?
不,它会被处理一次.
它是一样的:
public IEnumerable<Something> GetData() {
return someData;
}
foreach(var d in GetData()) {
//do something with [d]
}
Run Code Online (Sandbox Code Playgroud)
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
只会被处理一次.
更新:
请注意,这依赖于执行IEnumerator
的IEnumerable
用途.
在这个(邪恶的)例子中:
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
两次.