4

基于以下代码:

 var grouped = filters.GroupBy(p => p.PropertyName);
                 int numOfRowElements = grouped.Count();
     foreach (IGrouping<string, PropertyFilter> filter in grouped)
                {


                    foreach (var propertyFilter in filter)
                    {
                        // do something
                    }

                }

其中过滤一个列表,我的理解是调用 IEnumerable.Count() 会强制执行查询。此执行的结果是否存储在分组变量中,然后在 foreach 循环中使用,或者 foreach 循环是否强制再次执行查询?这样做会更好吗?

 var grouped = filters.GroupBy(p => p.PropertyName).ToList();
  int numOfRowElements = grouped.Count;
     foreach (IGrouping<string, PropertyFilter> filter in grouped)
                {


                    foreach (var propertyFilter in filter)
                    {
                        // do something
                    }

                }

TIA。

4

1 回答 1

5

如果底层数据源是IList<T>,Enumerable.Count()将调用该.Count属性作为优化,因此没有*性能损失。如果不是,则将强制进行枚举。仔细考虑这一点。

var someList = new List<int>(); 
var count = someList.Count(); // will use .Count property
var count = someList.OrderBy(x => x).Count(); // will force enumeration 

在此示例中,我只是在第二个语句中获取列表的计数。在第三个中,我对列表进行排序,然后进行计数。对列表排序会返回一个序列,而不是一个列表。因此,该Count()方法不适用于IList<T>,而是IEnumerable<T>。在这种情况下,必须枚举查询以获取结果,并且会产生随之而来的任何成本(在这种情况下是排序)。

鉴于此,在您的第一个片段中,您将枚举您的查询两次。一次获得计数,一次在 foreach 中。这将执行所有逻辑以将您的数据分组两次。您的第二个示例将只执行一次分组操作,同时显然迭代 foreach 中的结果列表,这应该比第二次执行分组操作更便宜。(您是否可以衡量节省完全取决于原始列表中数据的大小和/或来源。如有疑问,请对其进行分析。)


*间接层可能会有一个的测量惩罚,如果你认为它是一个真正的瓶颈,你将不得不对此进行分析。但将Count()方法视为

if (sequence is IList<T>) 
{
    return ((IList<T>)sequence).Count
}
else 
{
   /* perform enumeration */;
}
于 2011-10-05T15:51:58.733 回答