我知道IEnumerable<T>
在调用之前不会迭代。
假设我有这段代码:
foreach(int iteratorInt in myIEnumerable.OrderBy(x => x))
{
if(iteratorInt == myIEnumerable.First())
{
// do something
}
}
在if
我正在检查第一个元素,所以每次迭代都必须对myIEnumerable
进行排序,以查看哪个是第一个元素,或者它只被排序一次?
答案 0 :(得分:1)
您的可枚举只会已订购一次,此处:myIEnumerable.OrderBy(x => x)
在此行if(iteratorInt == myIEnumerable.First())
,它不会再次订购。
也许您误解了IEnumerable.First
方法,IEnumerable.First
和IEnumerable.OrderBy
方法之间没有关系。
Console.WriteLine(new [] {3, 2, 1}.First());
// here you get 3, not 1.
您可以在此处看到自定义OrderBy
方法:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var myIEnumerable = GetMyEnumerable();
foreach(var item in myIEnumerable.MyCustomOrderBy(x => x))
{
if(item == myIEnumerable.First())
{
Console.WriteLine("The condition is true with: " + item);
}
}
}
public static IEnumerable<int> GetMyEnumerable()
{
foreach(var i in new int[] {5, 4, 3, 2, 1})
{
Console.WriteLine("GetMyEnumerable was called " + i);
yield return i;
}
}
}
public static class OrderByExtensionMethod
{
public static IOrderedEnumerable<TSource> MyCustomOrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
Console.WriteLine("OrderByExtensionMethod was called");
return source.OrderBy(keySelector);
}
}
输出:
OrderByExtensionMethod was called
GetMyEnumerable was called 5
GetMyEnumerable was called 4
GetMyEnumerable was called 3
GetMyEnumerable was called 2
GetMyEnumerable was called 1
GetMyEnumerable was called 5
GetMyEnumerable was called 5
GetMyEnumerable was called 5
GetMyEnumerable was called 5
GetMyEnumerable was called 5
The condition is true with: 5
发生了什么事?
首先调用MyCustomOrderBy
方法,他需要迭代整个集合来对元素进行排序。
OrderByExtensionMethod was called
GetMyEnumerable was called 5
GetMyEnumerable was called 4
GetMyEnumerable was called 3
GetMyEnumerable was called 2
GetMyEnumerable was called 1
然后你的foreach开始,并为每个项目执行myIEnumerable.First()
:
GetMyEnumerable was called 5
GetMyEnumerable was called 5
GetMyEnumerable was called 5
GetMyEnumerable was called 5
GetMyEnumerable was called 5
最后,你得到你想要的东西:
The condition is true with: 5
答案 1 :(得分:1)
使用LINQ扩展时,查询将仅在请求时执行,也称为延迟执行。当多次请求相同的查询时,每次都会重新评估基础查询,除非初始查询已使用string = string.replaceAll("(?U)[^-_/.,A-Za-zÀ-ÿ &&[^×÷]]+","");
或.ToArrary()
之类的内容实现。
这个问题并不完全清楚,所以我将提供一些展示各种行为的例子。
Ex 1:
代码:
.ToList()
前2:
代码:
private static void Ex1()
{
Console.WriteLine("A");
IEnumerable<int> myIEnumerable = GetEnumerable();
Console.WriteLine("B");
foreach (int i in myIEnumerable.OrderBy(x => x))
{
Console.WriteLine("*** foreach : " + i);
if (i == myIEnumerable.First())
{
Console.WriteLine("=== Matched .First() : " + i);
}
}
Console.WriteLine("C");
}
前3:
代码:
private static void Ex2()
{
Console.WriteLine("A");
IEnumerable<int> myIEnumerable = GetEnumerable();
Console.WriteLine("B");
var ordered = myIEnumerable.OrderBy(x => x);
foreach (int i in ordered)
{
Console.WriteLine("*** foreach : " + i);
if (i == ordered.First())
{
Console.WriteLine("=== Matched .First() : " + i);
}
}
Console.WriteLine("C");
}
所有查询都使用相同的方法来获取可枚举的内容:
private static void Ex3()
{
Console.WriteLine("A");
IEnumerable<int> myIEnumerable = GetEnumerable();
Console.WriteLine("B");
var ordered = myIEnumerable.OrderBy(x => x).ToArray();
foreach (int i in ordered)
{
Console.WriteLine("*** foreach : " + i);
if (i == ordered.First())
{
Console.WriteLine("=== Matched .First() : " + i);
}
}
Console.WriteLine("C");
}
结果将最终为:
private static IEnumerable<int> GetEnumerable()
{
Console.WriteLine("~~~ GetEnumerable Start");
foreach (int i in new[]{3, 2, 1})
{
Console.WriteLine(">>> yield return : " + i);
yield return i;
}
Console.WriteLine("~~~ GetEnumerable End");
}
答案 2 :(得分:0)
代码:
foreach(int iteratorInt in myIEnumerable.OrderBy(x => x.MyProperty))
OrderBy
只执行一次
答案 3 :(得分:0)
OrderBy
仅评估一次,但是,每次迭代都会创建一个基于原始无序IEnumerator<T>
的新myIEnumerable
,它可能与iteratorInt
不匹配在第一次迭代中,除非第一个元素恰好是排序到第一个位置的东西。
如果您 希望第一次迭代的iteratorInt
值与可枚举的First()
结果相匹配。你想在循环之前创建有序可枚举的临时副本,如下所示:
var list = myIEnumerable.OrderBy(x => x);
foreach(int iteratorInt in list)
{
if(iteratorInt == list.First())
{
// do something
}
}
虽然这是一个相当无意义的模式(类似于&#34; Loop-switch&#34;反模式),因为它可以简化为:
//do something with list.First();