Find() vs. Where().FirstOrDefault()
我经常看到人们使用Where.FirstOrDefault()进行搜索并获取第一个元素。为什么不直接使用Find()?有什么优势吗?我看不出有什么不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| namespace LinqFindVsWhere
{
class Program
{
static void Main (string[] args )
{
List <string> list = new List <string>();
list .AddRange(new string[]
{
"item1",
"item2",
"item3",
"item4"
});
string item2 = list .Find(x => x =="item2");
Console .WriteLine(item2 == null ?"not found" :"found");
string item3 = list .Where(x => x =="item3").FirstOrDefault();
Console .WriteLine(item3 == null ?"not found" :"found");
Console .ReadKey();
}
}
} |
- fwiw,list.FirstOrDefault(x => x =="item3");比使用.Where和.FirstOrDefault更简洁。
- @柯克,我想我的下一个问题是他们为什么要加上这个发现。这是个好消息。我唯一能想到的是FirstOrDefault可以返回一个与空不同的默认值。否则,它就像是一个毫无意义的加法。
- Find早于linq。(它在.NET 2.0中提供,您不能使用lambda。你被迫使用普通方法或匿名方法)
IEnumerable上的Find方法在哪里?(反问句)
Where和FirstOrDefault方法适用于多种序列,包括List、T[]、Collection等,任何实现IEnumerable的序列都可以使用这些方法。Find仅适用于List。通常更适用的方法,然后更可重用并具有更大的影响。
I guess my next question would be why did they add the find at all. That is a good tip. The only thing I can think of is that the FirstOrDefault could return a different default value other than null. Otherwise it just seems like a pointless addition
List上的Find比其它方法早。List在.NET 2.0中添加了泛型,Find是该类API的一部分。添加了Where和FirstOrDefault作为带有linq的IEnumerable的扩展方法,linq是较新的.NET版本。我不能肯定地说,如果linq与2.0版本一起存在,那么Find将永远不会被添加,但可以肯定的是,早期.NET版本中的许多其他功能已经被后期版本废弃或冗余。
- 回答得很好。谢谢您。
- 仅作补充:不需要调用Where和First或FirstOrDefault:First或FirstOrDefault允许您指定搜索谓词,使Where调用不必要
- 但是,Where(condition).FirstOrDefault()至少也可以优化,有时甚至比单用FirstOrDefault(condition)更好。我们总是使用Where()来提高可用的性能。
我今天刚刚发现,在一个80K对象列表上做了一些测试,发现Find()比使用FirstOrDefault()的Where快1000%。我不知道这一点,直到前后测试了一个计时器。有时是同一时间,否则就更快了。
- 你是在哪里和第一个还是默认的情况下尝试的?如果您这样做了,可能只使用first或default进行尝试,看看find()是否更好。
- @请看这里。发现的速度真的快了差不多两倍。但我不明白这仅仅是因为没有枚举器开销吗?
- 这听起来好像您没有用.ToList()或.ToArray()实现实际执行查询的结果。
- 这是因为Find使用主键(因此是索引),而Where是普通的SQL查询。
- 如果没有主键?在那些情况下,我总是使用FindBy…
- 在EF6中,find和firstordefault都生成完全相同的SQL语句。通过执行context.database.log=console.write,您可以在控制台应用程序中看到SQL;站点示例使用内存中的字符串列表"find",而不是使用主键的数据库。在这种情况下,find子句的语句转换(省略了对lambda表达式解析的需要)可能是性能提高的原因。对于数据库,我怀疑您会注意到RL情况的不同…我还想知道它是否是用find first而不是find second测试的…
- 嗯,这种性能改进是因为find()在命中db之前签入对象的缓存,而where()总是转到db来获取对象
- 这与Linq to实体相关,而不是与原始海报指定的对象相关。
Find只在List中执行,而Where().FirstOrDefault()与所有IEnumerable一起工作。
如果数据源是实体框架,则有一个非常重要的区别:Find将发现处于"添加"状态的实体尚未持久化,但Where将不会持久化。这是按设计的。
除了安东尼的回答Where()访问所有记录,然后返回结果,而Find()如果谓词与给定谓词匹配,则不需要遍历所有记录。
假设您有一个具有id和name属性的测试类列表。
1 2 3 4 5 6 7
| List <Test > tests = new List <Test >();
tests .Add(new Test () { Id = 1, Name ="name1" });
tests .Add(new Test () { Id = 2, Name ="name2" });
tests .Add(new Test () { Id = 3, Name ="name3" });
tests .Add(new Test () { Id = 4, Name ="name2" });
var r = tests .Find(p => p .Name =="name2");
Console .WriteLine(r .Id); |
会给出2的输出,只有2次访问才能给出结果,但如果您使用Where().FirstOrDefault(),我们将访问所有记录,然后得到结果。
所以,当你知道你只想从收集的记录中得到第一个结果时,Find()比Where().FirtorDefault();更合适。