检查和检索集合的第一项的最佳方法是什么?
我知道这有点微不足道,但是...
获取集合的第一项(如果存在)的参考的最佳方法是什么?假设集合包含引用类型的项目。
代码示例 1:
if (collection.Any())
{
var firstItem = collection.First();
// add logic here
}
上面的示例对集合进行了两次单独的调用,开始迭代,一旦检测到第一个迭代,迭代就会完成。
代码示例 2:
var firstItem = collection.FirstOrDefault();
if (firstItem != null)
{
// add logic here
}
上面的示例仅对集合进行了一次调用,但引入了一个在更广泛范围内不必要的变量。
是否有与此场景相关的最佳实践?有更好的解决方案吗?
I understand this is somewhat trivial but...
What the best way to get the reference the first item of a collection if any exist? Assume the collection contains items of a reference-type.
Code Sample 1:
if (collection.Any())
{
var firstItem = collection.First();
// add logic here
}
The above sample has two separate calls on the collection starting an iteration which complete as soon as the first is detected.
Code Sample 2:
var firstItem = collection.FirstOrDefault();
if (firstItem != null)
{
// add logic here
}
The above sample only has a single call on the collection but introduces a variable that is unnecessarily in a wider scope.
Is there a best-practices related to this scenario? Is there a better solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
我更喜欢第二个例子,因为它在一般情况下更有效。该集合可能是许多不同的延迟评估 LINQ 查询的组合,因此即使获取第一个元素也需要大量的工作。
例如,假设该集合是根据以下 LINQ 查询构建的,
仅从
collection
中获取第一个元素需要对originalList
的内容进行完整排序。每次计算collection
的元素时都会发生这种完整排序。第一个示例导致潜在昂贵的集合被评估两次:通过
Any
和First
方法。第二个示例仅评估集合一次,因此我会选择它而不是第一个。I prefer the second example because it's more effecient in the general case. It's possible that this collection is combination of many different delay evaluated LINQ queries such that even getting the first element requires a non-trivial amount of work.
Imagine for example that this collection is build from the following LINQ query
Getting just the first element out of
collection
requires a full sort of the contents oforiginalList
. This full sort will occur each time the elements ofcollection
are evaluated.The first sample causes the potentially expensive collection to be evaluated twice: via the
Any
andFirst
method. The second sample only evaluates the collection once and hence I would choose it over the first.您可以创建这样的扩展方法:
然后您可以像这样使用它:
You could create an extension method like this:
Then you would use it like this:
第二个不适用于不可为 null 的值类型(编辑: 正如您所假设的 - 第一次错过了),并且除了第一个(具有竞争条件)之外实际上没有其他选择。有两种合适的替代方案 - 选择其中一种取决于您获得空序列的频率。
如果这是一种常见或预期的情况,您得到一个空枚举,那么使用
foreach
循环相对简洁:或者如果您确实不希望其中出现
break
(其中是可以理解的):如果它为空相对不常见,那么 try/catch 块应该提供最佳性能(因为异常只有在实际引发时才昂贵 - 未引发的异常实际上是免费的) ):
第三种选择是直接使用枚举器,尽管这应该与
foreach
版本相同,并且稍微不太清楚:The second doesn't work on non-nullable value types (Edit: as you assumed - missed that the first time) and doesn't really have an alternative besides the first, which has a race-condition. There are two alternatives which are both suitable - selecting one or the other depends on how frequently you will get an empty sequence.
If it's a common or expected case where you get an empty enumeration, using a
foreach
loop is relatively neat:or if you really don't want the
break
in there (which is understandable):If it is relatively unusual for it to be empty then a
try/catch
block should give the best performance (since exceptions are only expensive if they are actually raised - an unraised exception is practically free):A third option is to use an enumerator directly, though this should be identical to the
foreach
version and is slightly less clear:有时我会使用这种模式:
它仅启动一次迭代(因此它比代码示例 1 更好),并且变量
firstItem
的范围限制在括号内(因此它比代码示例 2 更好)。Sometimes I use this pattern:
It initiates only one iteration (so it's better than Code Sample 1) and the scope of the variable
firstItem
is limited inside the brackets (so it's better than Code Sample 2).或者,作为 Gabe 解决方案的扩展,让它使用 lambda,这样您就可以删除 if:
并像这样使用它:
Or, as an extension to the solution from Gabe, make it use a lambda so you can drop the if:
And use it like:
由于所有通用
Collections
(即:类型为 System.Collections.ObjectModel) 具有Count
成员,我的首选方法如下:这是安全的,因为所有集合都将具有
Count
和Item
属性。对于任何其他阅读您的代码的程序员来说,它也非常直接且容易理解您的意图。Since all generic
Collections
(ie: of type System.Collections.ObjectModel) have theCount
member my preferred way of doing this is as follows:This is safe is since all Collections will have both the
Count
andItem
property. Its also very straight forward and easy for any other programmers reading your code to understand what your intent is.刚刚对原始类型进行了简单的测试,看起来您的代码示例 #2 在这种情况下最快(已更新):
AnyFirst
非空:00:00:00.0000262 秒
EmptySet: 00:00:00.0000174 秒
ForLoop
非空:00:00:00.0000158 秒
EmptySet: 00:00:00.0000151 秒
NullCheck
非空:00:00:00.0000088 秒
EmptySet: 00:00:00.0000064 秒
TryGetFirst
非空:00:00:00.0000177 秒
空集:00:00:00.0000172 秒
Just did simple test on primitive type, and looks like your code sample #2 is fastest in this case (updated):
AnyFirst
NonEmpty: 00:00:00.0000262 seconds
EmptySet: 00:00:00.0000174 seconds
ForLoop
NonEmpty: 00:00:00.0000158 seconds
EmptySet: 00:00:00.0000151 seconds
NullCheck
NonEmpty: 00:00:00.0000088 seconds
EmptySet: 00:00:00.0000064 seconds
TryGetFirst
NonEmpty: 00:00:00.0000177 seconds
EmptySet: 00:00:00.0000172 seconds