C# 使用LINQ where(lamdaexp).First和First(lambdaexp)
以下两种方法有什么不同吗?我得到了同样的结果,但我正在努力理解哪一个是正确的和有效的 方法1:C# 使用LINQ where(lamdaexp).First和First(lambdaexp),c#,linq,lambda,C#,Linq,Lambda,以下两种方法有什么不同吗?我得到了同样的结果,但我正在努力理解哪一个是正确的和有效的 方法1: Product product12 = products.Where(p => p.ProductID == 12).First(); 方法2: Product prod12 = products.First(p => p.ProductID == 12); 它们在功能上是等价的,同样有效。LINQ构建一个查询,在枚举结果之前不会对其求值,例如foreach循环或在本例中是First(
Product product12 = products.Where(p => p.ProductID == 12).First();
方法2:
Product prod12 = products.First(p => p.ProductID == 12);
它们在功能上是等价的,同样有效。LINQ构建一个查询,在枚举结果之前不会对其求值,例如foreach循环或在本例中是First()操作 因此,两者都将按原始顺序计算项目,直到找到ProductID==12的第一个实例,如果找到,则返回该实例(如果没有找到,则抛出异常) 也就是说,后一种方法是我首选的方法,因为它更简洁,而且通常更易于阅读。(我假设您使用的是Linq to.Net)
首先让我们看看它们的源代码: 这是: 让我们来找出每种代码的作用:
products.First(p=>p.ProductID==12)代码>
First()
的源代码,我们可以说,First()
将在集合上迭代,并在找到符合条件的集合中的第一项时停止迭代
products.Where(p=>p.ProductID==12.First()代码>
Where
方法中创建迭代器,其中元素满足条件。然后,它再次将get第一个元素添加到该迭代器中。并且,将在找到第一个元素时再次返回该元素
作为补充说明,LINQ在某些方法中使用了延迟执行。这和你问题的结果有一定的关系
延迟执行是执行模型的一种模式
CLR确保仅在需要时从中提取值
基于IEnumerable的信息源。当任何Linq运算符
使用延迟执行,CLR封装相关的
信息,例如原始序列、谓词或选择器(如果
any)转换为一个迭代器,在生成信息时将使用该迭代器
使用ToList方法从原始序列中提取,或
ForEachmethod或手动使用基础GetEnumerator和
C#中的MoveNext方法
问题是哪一个更快?
要点是,
Where().First
比First
快。如果是列表
和数组
。否则,First()
会更快
让我们关注Where()
实现。如果您的集合是List,它将返回WhereListIterator()
,但First()
将只在源代码上迭代。
在我看来,他们在WhereListIterator
的应用程序中取得了一些进展。在此之后,我们将调用First()
方法,该方法不接受任何谓词作为输入,只对过滤后的集合进行迭代
另外,据我所知,其中的
迭代器避免了间接的虚拟表调用,而是直接调用迭代器方法。
这就是加快速度的原因。我认为您的问题更像是:
之前,将其中
迭代整个集合吗
首先也会这样做吗
编写了自己的实现,其中
和首先
这个示例不是确切的.net实现,但它在相同的概念下工作
public static class Extensions
{
public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> collection, Func<T,bool> condition)
{
foreach(var item in collection)
{
if(condition(item))
{
yield return item;
}
}
}
public static T MyFirst<T>(this IEnumerable<T> collection, Func<T,bool> condition)
{
foreach (var item in collection)
{
if (condition(item))
{
return item;
}
}
throw new InvalidOperationException("No element found");
}
}
公共静态类扩展
{
公共静态IEnumerable MyWhere(此IEnumerable集合,Func条件)
{
foreach(集合中的var项)
{
如果(条件(项目))
{
收益回报项目;
}
}
}
公共静态T MyFirst(此IEnumerable集合,Func条件)
{
foreach(集合中的var项)
{
如果(条件(项目))
{
退货项目;
}
}
抛出新的InvalidOperationException(“未找到元素”);
}
}
执行以下代码:
List<int> myList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var five = myList.MyWhere(i => i < 6).MyFirst(i => i == 5);
List myList=新列表{1,2,3,4,5,6,7,8,9,10};
var-five=myList.MyWhere(i=>i<6).MyFirst(i=>i==5);
在
MyWhere
和MyFirst
foreach
中放置一个调试器断点,开始了解使用Linq To对象处理迭代器时发生的情况。我刚刚运行了一个测试,您可以在.Net FIDLE上看到结果
真正的答案是,哪个更快取决于应用的过滤器类型和迭代的集合类型
Func<Item,bool> filter = x => x.Size == 200;
Run("First", () => items.First( filter ));
Run("Where First", () => items.Where( filter ).First());
88 milliseconds for First
69 milliseconds for Where First
filter = x => x.Size < 200;
Run("First", () => items.First( filter ));
Run("Where First", () => items.Where( filter ).First());
2 milliseconds for First
4 milliseconds for Where First
filter = x => x.Size > 200;
Run("First", () => items.First( filter ));
Run("Where First", () => items.Where( filter ).First());
88 milliseconds for First
71 milliseconds for Where First
Func filter=x=>x.Size==200;
运行(“第一个”,()=>items.First(过滤器));
运行(“Where First”,()=>items.Where(filter.First());
第一次为88毫秒
69毫秒,第一个在哪里
过滤器=x=>x。尺寸<200;
运行(“第一个”,()=>items.First(过滤器));
运行(“Where First”,()=>items.Where(filter.First());
第一次为2毫秒
4毫秒,第一个在哪里
过滤器=x=>x。尺寸>200;
运行(“第一个”,()=>items.First(过滤器));
运行(“Where First”,()=>items.Where(filter.First());
第一次为88毫秒
71毫秒,第一个在哪里
因此没有明确的答案
另一个测试,一直以来,First比Where First快
更新
分析List类后,发现Where().First()只比First()快,仅在List和Array的情况下,它不适用于IQueryable或任何其他形式的Enumerable。原因是,列表中使用的枚举数不是每个线程缓存的。List总是创建新的枚举数,所以First()使用List的枚举数(迭代器)
在列表的Where()中使用的WhereListIterator不会创建新的枚举数,而是在线程中缓存当前迭代器。这使得Where().First()运行更快
但是,这种缓存ListIterator的操作有一些缺点
List<int> myList = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
var five = myList.MyWhere(i => i < 6).MyFirst(i => i == 5);
Func<Item,bool> filter = x => x.Size == 200;
Run("First", () => items.First( filter ));
Run("Where First", () => items.Where( filter ).First());
88 milliseconds for First
69 milliseconds for Where First
filter = x => x.Size < 200;
Run("First", () => items.First( filter ));
Run("Where First", () => items.Where( filter ).First());
2 milliseconds for First
4 milliseconds for Where First
filter = x => x.Size > 200;
Run("First", () => items.First( filter ));
Run("Where First", () => items.Where( filter ).First());
88 milliseconds for First
71 milliseconds for Where First