咨询区
KingOfHypocrites:
我经常看到别人用 Where.FirstOrDefault()
获取某一个匹配集合的第一个元素,我在想为什么他们不使用 Find()
呢 ? 是不是前者更高级一点?有人能告诉我它们的差别吗?
比如下面的代码:
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();}}
}
回答区
Abhinav Galodha:
在 IEnumerable<T>
上你能找到 Find
吗?
Where
和 FirstOrDefault
可用在多种序列集合上,包括:List<T>, T[], Collection<T>
等等,任何实现了 IEnumerable<T>
的集合都可以使用这两个方法。
Find
仅仅是在 List<T>
上可用。
M Muneeb Ijaz:
它们两者的区别在于,Where()
方法会遍历所有的记录然后再返回结果,而 Find()
方法则不会遍历所有记录,它只需遇到指定的 predicate
满足后即可返回。
我用 List<Test>
来做一个演示。
class Program{static void Main(string[] args){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);}}class Test{public int Id { get; set; }public string Name { get; set; }}
为了能找到图中的 2
,Find 方法只需访问两次记录即可, 而 Where().FirstOrDefault()
则需访问 4
次,也就是全盘遍历。
点评区
汇总两位大佬的答案就是:易用
和 性能
绝对是成反比的,比如你知道的 ADO.NET
和 EntityFramework
, 又或者是 汇编
和 C#
...
其次要想深究,我觉得可以多用用 ILSpy
去挖挖源码。
// System.Collections.Generic.List<T>
public T Find(Predicate<T> match)
{if (match == null){ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);}for (int i = 0; i < _size; i++){if (match(_items[i])){return _items[i];}}return default(T);
}// System.Linq.Enumerable
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source)
{if (source == null){throw Error.ArgumentNull("source");}IList<TSource> list = source as IList<TSource>;if (list != null){if (list.Count > 0){return list[0];}}else{using (IEnumerator<TSource> enumerator = source.GetEnumerator()){if (enumerator.MoveNext()){return enumerator.Current;}}}return default(TSource);
}