在系统中。Linq命名空间,我们现在可以扩展我们的IEnumerable来拥有Any()和Count()扩展方法。

最近有人告诉我,如果我想检查一个集合中是否包含1个或多个项目,我应该使用. any()扩展方法而不是. count() > 0扩展方法,因为. count()扩展方法必须遍历所有项目。

其次,一些集合具有Count或Length属性(而不是扩展方法)。使用这些,而不是.Any()或.Count()会更好吗?

-是的-不?


当前回答

使用Count()来测试是否为空,但使用Any()可以使意图更清晰,代码更可读。然而,有一些情况需要特别注意:

如果集合是一个EntityFramework或其他ORM查询,调用Count()将导致执行一个潜在的大规模SQL查询,并可能给应用程序数据库带来很大的开销。调用Any()也将连接到数据库,但将生成更高效的SQL。

如果集合是包含创建对象的Select()语句的LINQ查询的一部分,则可能会不必要地分配大量内存。调用Any()将更有效,因为它将执行更少的枚举迭代。

使用Any()的示例:

private static bool IsEmpty(IEnumerable<string> strings)
{
  return !strings.Any();
}

其他回答

如果您正在使用实体框架,并且有一个包含许多记录的巨大表,Any()将会更快。我记得有一次,我想检查一个有数百万行的表是否为空。Count() > 0完成耗时20-30秒。Any()是即时的。

Any()可以提高性能,因为它可能不必迭代集合来获得事物的数量。只要击中其中一个就行。或者,对于LINQ-to-Entities,生成的SQL将是IF EXISTS(…)而不是SELECT COUNT…甚至选择* ....

编辑:在EF 6.1.1版本中修复。这个答案是不实际的

对于SQL Server和EF4-6, Count()的执行速度比Any()快两倍。

当你运行Table.Any()时,它会生成类似这样的东西(警告:不要伤害大脑试图理解它)

SELECT 
CASE WHEN ( EXISTS (SELECT 
    1 AS [C1]
    FROM [Table] AS [Extent1]
)) THEN cast(1 as bit) WHEN ( NOT EXISTS (SELECT 
    1 AS [C1]
    FROM [Table] AS [Extent2]
)) THEN cast(0 as bit) END AS [C1]
FROM  ( SELECT 1 AS X ) AS [SingleRowTable1]

这需要对符合条件的行进行两次扫描。

我不喜欢写Count() > 0,因为它隐藏了我的意图。我更喜欢使用自定义谓词:

public static class QueryExtensions
{
    public static bool Exists<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
    {
        return source.Count(predicate) > 0;
    }
}

我已经使用IList创建了一个示例应用程序,其中包含100个元素到100万个项目,以查看Count vs Any哪个是最好的。

Code

class Program
{
    static void Main()
    {

        //Creating List of customers
        IList<Customer> customers = new List<Customer>();
        for (int i = 0; i <= 100; i++)
        {
            Customer customer = new Customer
            {
                CustomerId = i,
                CustomerName = string.Format("Customer{0}", i)
            };
            customers.Add(customer);
        }

        //Measuring time with count
        Stopwatch stopWatch = new Stopwatch();
        stopWatch.Start();
        if (customers.Count > 0)
        {
            Console.WriteLine("Customer list is not empty with count");
        }
        stopWatch.Stop();
        Console.WriteLine("Time consumed with count: {0}", stopWatch.Elapsed);

        //Measuring time with any
        stopWatch.Restart();
        if (customers.Any())
        {
            Console.WriteLine("Customer list is not empty with any");
        }
        stopWatch.Stop();
        Console.WriteLine("Time consumed with count: {0}", stopWatch.Elapsed);
        Console.ReadLine();

    }
}

public class Customer
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; }
}

结果:

任何都比数好。

如果您从具有. length或. count的东西开始(例如ICollection<T>, IList<T>, List<T>,等等),那么这将是最快的选项,因为它不需要通过Any()所要求的GetEnumerator()/MoveNext()/Dispose()序列来检查非空IEnumerable<T>序列。

对于IEnumerable<T>,则Any()通常会更快,因为它只需要查看一次迭代。但是,请注意Count()的LINQ-to-Objects实现确实检查ICollection<T>(使用.Count作为优化)-因此,如果您的底层数据源直接是一个列表/集合,则不会有很大的区别。不要问我为什么不使用非泛型的ICollection…

当然,如果你已经使用LINQ来过滤它(Where等),你将有一个基于迭代器块的序列,所以这个ICollection<T>优化是无用的。

通常,对于IEnumerable<T>:坚持使用Any();-p

使用Count()来测试是否为空,但使用Any()可以使意图更清晰,代码更可读。然而,有一些情况需要特别注意:

如果集合是一个EntityFramework或其他ORM查询,调用Count()将导致执行一个潜在的大规模SQL查询,并可能给应用程序数据库带来很大的开销。调用Any()也将连接到数据库,但将生成更高效的SQL。

如果集合是包含创建对象的Select()语句的LINQ查询的一部分,则可能会不必要地分配大量内存。调用Any()将更有效,因为它将执行更少的枚举迭代。

使用Any()的示例:

private static bool IsEmpty(IEnumerable<string> strings)
{
  return !strings.Any();
}