到 ToList() 还是不到 ToList()?

To ToList() or not to ToList()?

给定 在内存中 (不是 LINQ to SQL)类 列表:

List<MyClass> myItems = /*lots and lots of items*/;

我正在使用 GroupBy() 语句对其进行分组:

myItems.GroupBy(g => g.Ref)

然后立即在 foreach 循环中消耗在 "group" 上调用 .ToList() 有什么区别还是我应该只使用 IEnumerable.

如此完整的代码示例:

ToList()

List<List<MyClass>> groupedItemsA = new List<List<MyClass>>();
List<List<MyClass>> groupedItemsB = new List<List<MyClass>>();

List<MyClass> myItems = /*lots and lots of items*/;
List<IGrouping<string, MyClass>> groupedItems = myItems.GroupBy(g => g.Ref).ToList();
foreach(IGrouping<string, MyClass> item in groupedItems)
{
  if (/*check something*/)
  {
     groupedItemsA.Add(item.ToList());
  }
  else
  {
    groupedItemsB.Add(item.ToList());
  }
}

使用IEnumerable

List<List<MyClass>> groupedItemsA = new List<List<MyClass>>();
List<List<MyClass>> groupedItemsB = new List<List<MyClass>>();


List<MyClass> myItems = /*lots and lots of items*/;
IEnumerable<IGrouping<string, MyClass>> groupedItems = myItems.GroupBy(g => g.Ref);
foreach(IGrouping<string, MyClass> item in groupedItems)
{
  if (/*check something*/)
  {
     groupedItemsA.Add(item.ToList());
  }
  else
  {
    groupedItemsB.Add(item.ToList());
  }
}

这些"under the hood"的执行计划有什么区别吗?这两种方法会更有效还是真的无关紧要?

之后我使用groupedItems列表。

Is there any difference?

是,.ToList() 通过迭代分组集合创建一个新列表:

The ToList<TSource>(IEnumerable<TSource>) method forces immediate query evaluation and returns a List that contains the query results.

这是否明显应该由您进行基准测试。

如果你只迭代一次分组集合,.ToList()这一步是不必要的,而且会比直接枚举GroupBy()结果相对慢一些。

如果你确定你将只使用groupedItems一次,那么使用.ToList()有一个单一优势:如果在分组期间出现异常(例如,因为您的代码在计算 .Ref 时做了一些有趣的事情),异常将出现在 .ToList() 行中,而不是在 [=15] 行中=]...我不认为这是一个很大的优势(也许是一个劣势)。

澄清一下:

public class MyClass
{
    public string Ref
    {
        get
        {
            // sometimes I like to throw an exception!
            if (DateTime.Now.Ticks % 10 == 0) throw new Exception();

            return "Foo";
        }
    }
}

请注意,您已明确将此问题标记为 IEnumerable,并且在您的示例中 myItemsList<>,因此我不会讨论 [=] 的区别19=] 或当您通过实体 Framework/Linq 到 SQL.

从数据库读取数据时

是的,有区别,而且可能很重要。

ToList() 将迭代并将每个迭代项追加到新列表中。这具有创建消耗内存的临时列表的效果。

有时您可能想要承受内存损失,尤其是当您打算多次迭代列表并且原始列表不在内存中时。

在您使用 ToList() 的特定示例中,您实际上最终迭代了两次 - 一次是构建列表,第二次是在您的 foreach 中。根据列表的大小和您的应用程序,这可能是也可能不是问题。

如果您每次枚举时都使用 IEnumerable 而不是 List(),则 GroupBy 表达式将根据您的 myItems 列表重新求值.

这意味着如果您将另一个项目添加到 myItems 然后枚举它,该项目将包含在 GroupBy 表达式中。

当您调用 ToList 时,您会创建一个新列表,并且对 myItems 的任何更改都不会包含在 groupedItems 中。