在.NET Framework和.NET Core中,具体细节有所不同,但这也取决于你正在做什么:如果你使用
ICollection
或
ICollection<T>
类型(例如与
List<T>
一起使用),则有一个廉价访问的
.Count
属性,而其他类型可能需要枚举。
如果属性存在,请使用.Count > 0
,否则使用.Any()
。
使用
.Count() > 0
从来不是最好的选择,在某些情况下,它可能会明显变慢。
这适用于.NET Framework和.NET Core。
现在我们可以深入了解细节了...
列表和集合
让我们从一个非常常见的情况开始:使用 List<T>
(也是 ICollection<T>
)。
.Count
属性的实现方式如下:
private int _size;
public int Count {
get {
Contract.Ensures(Contract.Result<int>() >= 0);
return _size;
}
}
这段话的意思是,
_size
由
Add()
、
Remove()
等方法维护,由于它只是访问一个字段,因此这是一种极其廉价的操作——我们不需要迭代值。
ICollection
和
ICollection<T>
都有
.Count
属性,大多数实现它们的类型可能会以类似的方式实现。
其他
IEnumerable
类型(不是
ICollection
)需要开始枚举以确定它们是否为空。影响性能的关键因素是我们最终枚举单个项(理想情况)还是整个集合(相对昂贵)。
如果集合实际上导致I/O,例如从数据库或磁盘读取,这可能会对性能产生很大影响。
.NET Framework .Any()
在.NET Framework(4.8)中,Any()
的实现如下:
public static bool Any<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
using (IEnumerator<TSource> e = source.GetEnumerator()) {
if (e.MoveNext()) return true;
}
return false;
}
这意味着无论如何,它都会获得一个新的枚举器对象并尝试迭代一次。这比调用
List<T>.Count
属性更昂贵,但至少不会遍历整个列表。
.NET Framework(4.8)中,
Count()
实现基本上是:
public static int Count<TSource>(this IEnumerable<TSource> source)
{
ICollection<TSource> collection = source as ICollection<TSource>;
if (collection != null)
{
return collection.Count;
}
int num = 0;
using (IEnumerator<TSource> enumerator = source.GetEnumerator())
{
while (enumerator.MoveNext())
{
num = checked(num + 1);
}
return num;
}
}
如果可用,将使用{{ICollection.Count}},否则将枚举集合。
.NET Core .Any()
.NET Core中的LINQ Any()
实现更加智能。你可以在这里看到完整的源代码,但与此讨论相关的部分如下:
public static bool Any<TSource>(this IEnumerable<TSource> source)
{
if (source is ICollection<TSource> collectionoft)
{
return collectionoft.Count != 0;
}
using (IEnumerator<TSource> e = source.GetEnumerator())
{
return e.MoveNext();
}
}
因为
List<T>
是
ICollection<T>
,所以这将调用
Count
属性(虽然它调用了另一个方法,但没有额外的分配)。
.NET Core的
.Count()
实现基本与.NET Framework相同(参见上文),因此如果可用,它将使用
ICollection.Count
,否则枚举集合。
source
摘要
.NET Framework
.NET Core
.Count > 0
是最好的选择,如果可用(ICollection
)
.Any()
也可以,它将执行ICollection.Count > 0
或枚举单个项目
.Count() > 0
不好,因为它会完全枚举