我对FirstOrDefault的“最佳实践”感到有点好奇。
我已经看过这个问题了,这个问题与我的问题类似,但不够接近我回答我的问题。
其中哪些是“更好的代码”?为什么?
var foos = GetMyEnumerableFoos();
var foo1 = (from f in foos
where f.Bar == "spider monkey"
select f).FirstOrDefault();
/* OR */
var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey");
我倾向于后者,作为IMO,它使代码更清晰。但我很好奇,对于那些正在发生的事情的技术“胆量”是否更有效率。如果您使用不同类型的IEnumerables,这会改变吗?像DataTables或字符串数组或LINQ对象?
======编辑==========
假设Jon Skeet的帖子是正确的,我去了Reflector看看Where和FirstOrDefault的样子,这就是我想出的:
对于foos.Where(f => f.Bar ==“蜘蛛猴”)。FirstOrDefault()
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
if (source is Iterator<TSource>)
{
return ((Iterator<TSource>) source).Where(predicate);
}
if (source is TSource[])
{
return new WhereArrayIterator<TSource>((TSource[]) source, predicate);
}
if (source is List<TSource>)
{
return new WhereListIterator<TSource>((List<TSource>) source, predicate);
}
return new WhereEnumerableIterator<TSource>(source, predicate);
}
将提供:
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);
}
对于foos.FirstOrDefault(f =&gt; f.Bar ==“蜘蛛猴”);
public static TSource FirstOrDefault<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw Error.ArgumentNull("source");
}
if (predicate == null)
{
throw Error.ArgumentNull("predicate");
}
foreach (TSource local in source)
{
if (predicate(local))
{
return local;
}
}
return default(TSource);
}
看着这仍然让我有点困惑,通过对某些对象类型使用适当的迭代器会增加效率吗?或者是否更有效地跳过所有这些并开始循环并测试?我的直觉再次告诉我它是后者。
答案 0 :(得分:18)
好吧,编辑器会删除“select”部分,所以你真的在比较:
foo.Where(f => f.Bar == "spider monkey")
.FirstOrDefault()
VS
foo.FirstOrDefault(f => f.Bar == "spider monkey")
我怀疑它会在LINQ to Objects中对效率产生任何显着的差异。我本人亲自使用后一版本...除非我想在其他地方重用查询的过滤部分。
答案 1 :(得分:4)
我更喜欢后者,因为它更简洁。
效率条款我怀疑你能找到它们之间的实质性差异。它们的行为几乎完全相同,即使在实践中它们的工作略有不同。
最大的区别是第一个实例创建了一个新的IEnumerable<T>
实例,然后为第一个元素进行了操作。在后一种情况下,现有IEnumerable<T>
实例将与第一个匹配谓词的值一起走动。再一次,不太可能被注意到。
答案 2 :(得分:-1)
第二个版本会更有效率。
第一个版本
var foo1 = (from f in foos
where f.Bar == "spider monkey"
select f).FirstOrDefault();
将始终遍历所有项目,创建匹配项目的新集合。
第二个版本
var foo2 = foos.FirstOrDefault(f => f.Bar == "spider monkey");
只会遍历项目,直到找到匹配项,然后返回。