在LINQ查询中调用ToList()或ToArray()会更好吗?

我经常遇到这样的情况,我想在我声明的位置上对查询进行评估。 这通常是因为我需要迭代多次计算起来很昂贵。 例如:

string raw = "..."; var lines = (from l in raw.Split('\n') let ll = l.Trim() where !string.IsNullOrEmpty(ll) select ll).ToList(); 

这工作正常。 但是,如果我不打算修改结果,那么我不如调用ToArray()而不是ToList()

然而,我不知道是否ToArray()是通过首先调用ToList()来实现的,因此与调用ToList()相比内存效率更低。

我疯了吗? 我应该只是调用ToArray() – 安全和安全的知识,内存不会被分配两次?

除非你只需要一个数组来满足其他限制,否则你应该使用ToList 。 在大多数情况下, ToArray将分配比ToList更多的内存。

两者都使用数组来存储,但ToList有一个更灵活的约束。 它需要的数组至less与集合中元素的数量一样大。 如果数组较大,那不是问题。 但是, ToArray需要的数组的大小正好与元素的数量。

为了满足这个约束, ToArray经常比ToList做更多的分配。 一旦它有一个足够大的数组,它将分配一个完全正确的大小的数组,并将元素复制回该数组中。 唯一可以避免的是,当数组的增长algorithm恰好与需要存储的元素的数量一致时(绝对是less数)。

编辑

有几个人问我在List<T>值中有多余的未使用内存的结果。

这是一个有效的关注。 如果创build的集合是长期存在的,在创build之后永远不会被修改,并且有很高的登陆Gen2堆的机会,那么您最好ToArray分配额外的分配。

一般来说,虽然我觉得这是比较罕见的情况。 看到大量的ToArray调用会更常见,这些调用会立即传递给其他短暂的内存使用,在这种情况下, ToList显然更好。

这里的关键是进行configuration文件,然后再configuration文件。

性能差异将是微不足道的,因为List<T>被实现为dynamic大小的数组。 调用ToArray() (它使用内部的Buffer<T>类来增长数组)或ToList() (它调用List<T>(IEnumerable<T>)构造函数)最终将成为一个将它们放入一个数组,并增长数组,直到它适合所有。

如果您希望具体确认这一事实,请查看Reflector中有关方法的实现 – 您将看到它们归结为几乎相同的代码。

我同意@mquander的performance差异应该是微不足道的。 但是,我想要确定它的基准,所以我做了 – 这是微不足道的。

 Testing with List<T> source: ToArray time: 1934 ms (0.01934 ms/call), memory used: 4021 bytes/array ToList time: 1902 ms (0.01902 ms/call), memory used: 4045 bytes/List Testing with array source: ToArray time: 1957 ms (0.01957 ms/call), memory used: 4021 bytes/array ToList time: 2022 ms (0.02022 ms/call), memory used: 4045 bytes/List 

每个源数组/列表有1000个元素。 所以你可以看到,时间和记忆的差异是微不足道的。

我的结论是:不如使用ToList() ,因为List<T>比数组提供更多的function,除非几个字节的内存真的对你很重要。

内存将永远被分配两次 – 或接近。 由于您无法调整数组的大小,因此这两种方法都会使用某种机制来收集不断增长的集合中的数据。 (好吧,List本身就是一个越来越多的集合。)

列表使用数组作为内部存储,并在需要时将容量加倍。 这意味着平均2/3的物品至less被重新分配一次,其中一半重新分配至less两次,一半重新分配至less三次,等等。 这意味着每个项目平均被重新分配了1.3次,这不是很大的开销。

还要记住,如果您正在收集string,集合本身只包含对string的引用,则string本身不会被重新分配。

如果您在IEnumerable<T> (例如,来自ORM)上使用ToList() ,通常首选ToList() )。 如果序列的长度在开始时是未知的, ToArray()会创build像List一样的dynamic长度集合,然后将其转换为数组,这会花费额外的时间。

编辑 :这个答案的最后一部分是无效的。 但是,其余的仍然是有用的信息,所以我会离开它。

我知道这是一个老post,但是在提出同样的问题并做了一些研究之后,我发现了一些值得分享的有趣的东西。

首先,我同意@mquander和他的回答。 他在performance上是正确的,两者是相同的。

不过,我一直在使用Reflector来看看System.Linq.Enumerable扩展名称空间中的方法,并且我注意到了一个非常常见的优化。
只要有可能, IEnumerable<T>源被转换为IList<T>ICollection<T>来优化该方法。 例如,查看ElementAt(int)

有趣的是,微软select只为IList<T>优化,而不是IList 。 它看起来像微软喜欢使用IList<T>接口。

System.Array只实现IList ,所以它不会从任何这些扩展优化中受益。
因此,我认为最好的做法是使用.ToList()方法。
如果使用任何扩展方法,或将该列表传递给另一个方法,则有可能针对IList<T>进行优化。

你应该根据理想的deviseselect来决定去ToList还是ToArray 。 如果您想要一个只能被索引迭代和访问的集合,请selectToArray 。 如果您希望在稍后添加和从集合中删除的附加function没有太多麻烦,那么做一个ToList (不是真的,你不能添加到一个数组,但这通常不是正确的工具)。

如果性能很重要,你还应该考虑什么更快的操作。 实际上,你不会调用ToListToArray一百万次,但是可能在获得的集合上工作一百万次。 在这方面[]更好,因为List<>[]有一些开销。 看看这个线程的效率比较: 哪一个更有效率:List <int>或int []

在我刚才的testing中,我发现ToArray速度更快。 而且我不确定这些testing是如何扭曲的。 性能差异是如此微不足道,但只有在数百万次的循环中运行这些查询才会显着。

一个非常晚的答案,但我认为这将有助于谷歌。

当他们使用linq创build时,他们都会吮吸。 如果需要,它们都实现相同的代码来调整缓冲区大小ToArray内部使用一个类将IEnumerable<>转换为数组,通过分配一个4个元素的数组。 如果这还不够的话,可以通过创build一个新数组来扩大两倍的大小,并将当前数组复制到当前数组。 最后,它分配一个新的你的项目数。 如果你的查询返回129个元素,那么ToArray将进行6个分配和内存复制操作,以创build一个256个元素的数组,而不是另一个129的数组返回。 记忆效率非常高

ToList做同样的事情,但它会跳过最后的分配,因为你可以在将来添加项目。 列表不关心它是从linq查询创build还是手动创build。

对于创build列表更好的内存,但更糟糕的CPU,因为列表是一个通用的解决scheme,每一个行动需要范围检查除.net的内部范围检查数组。

因此,如果您将迭代遍历结果集太多次,那么数组是很好的,因为它意味着比列表更less的范围检查,编译器通常会优化数组以进行顺序访问。

如果您在创build时指定了容量参数,则List的初始化分配可能会更好。 在这种情况下,假设你知道结果大小,它将只分配一次数组。 ToList没有指定重载提供它,所以我们必须创build我们的扩展方法,创build一个给定容量的列表,然后使用List<>.AddRange

为了完成这个答案,我必须写下面的句子

  1. 最后,您可以使用ToArray或ToList,性能不会如此不同(请参阅@EMP的回答)。
  2. 你正在使用C#。 如果你需要性能,那么不要担心写高性能的代码,但担心不写性能不好的代码。
  3. 总是以高性能代码为目标。 AFAIK,x64 JIT基于C ++编译器,并执行一些有趣的事情,如尾recursion优化。
  4. 随着4.5你也可以享受简介指导优化和多核JIT。
  5. 最后,您可以使用asynchronous/等待模式来更快地处理它。

(七年后…)

其他一些(好的)答案集中在将发生的显微性能差异上。

这篇文章仅仅是提到数组( T[] )产生的IEnumerator<T>List<T>返回的语义差异的补充。

最好的例子说明:

 IList<int> source = Enumerable.Range(1, 10).ToArray(); // try changing to .ToList() foreach (var x in source) { if (x == 5) source[8] *= 100; Console.WriteLine(x); } 

上面的代码将不会exception运行,并生成输出:

  1
 2
 3
 4
五
 6
 7
 8
 900
 10 

这表明由int[]返回的IEnumarator<int>不会跟踪自从创build枚举数组以来是否修改了数组。

请注意,我将本地variablessource声明为IList<int> 。 通过这种方式,我确信C#编译器不会将foreach语句优化为等同于for (var idx = 0; idx < source.Length; idx++) { /* ... */ }循环的东西。 这是C#编译器可能做的事情,如果我使用var source = ...; 代替。 在我当前版本的.NET框架中,这里使用的实际枚举器是一个非公共的引用typesSystem.SZArrayHelper+SZGenericArrayEnumerator`1[System.Int32] ,当然这是一个实现细节。

现在,如果将.ToArray()更改为.ToList() ,则只会获得:

  1
 2
 3
 4
五 

后面跟着一个System.InvalidOperationException爆炸说:

collections被修改; 枚举操作可能无法执行。

在这种情况下,底层枚举器是公共可变值typesSystem.Collections.Generic.List`1+Enumerator[System.Int32] (在这种情况下盒装在IEnumerator<int>框中,因为我使用IList<int> )。

总之, List<T>生成的枚举器会跟踪枚举过程中列表是否更改,而T[]生成的枚举器不会。 因此,在.ToList().ToArray()之间进行select时请考虑这种差异。

人们通常会添加一个额外的 .ToArray().ToList()来绕开一个集合,该集合跟踪在枚举器的生命周期中是否被修改。

(如果有人想知道List<> 如何跟踪集合是否被修改,那么在这个类中有一个私有字段_version ,每次更新List<>都会改变它。

这是一个古老的问题 – 但为了用户的利益,他们偶然发现,也有“备忘录”Enumerable – 这有caching和停止Linq语句的多个枚举的效果,这是ToArray()和ToList()被使用了很多,即使从不使用列表或数组的集合属性。

Memoize可以在RX / System.Interactive库中find,这里解释: 更多的LINQ与System.Interactive

(从Bart De'Smet的博客 ,这是一个强烈推荐阅读,如果你正在与Linq的对象很多)

一种select是添加您自己的扩展方法,该方法返回只读的 ICollection<T> 。 当您不想使用数组/列表的索引属性,或者从列表中添加/删除时,这可能比使用ToListToArray更好。

 public static class EnumerableExtension { /// <summary> /// Causes immediate evaluation of the linq but only if required. /// As it returns a readonly ICollection, is better than using ToList or ToArray /// when you do not want to use the indexing properties of an IList, or add to the collection. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="enumerable"></param> /// <returns>Readonly collection</returns> public static ICollection<T> Evaluate<T>(this IEnumerable<T> enumerable) { //if it's already a readonly collection, use it var collection = enumerable as ICollection<T>; if ((collection != null) && collection.IsReadOnly) { return collection; } //or make a new collection return enumerable.ToList().AsReadOnly(); } } 

unit testing:

 [TestClass] public sealed class EvaluateLinqTests { [TestMethod] public void EvalTest() { var list = new List<int> {1, 2, 3}; var linqResult = list.Select(i => i); var linqResultEvaluated = list.Select(i => i).Evaluate(); list.Clear(); Assert.AreEqual(0, linqResult.Count()); //even though we have cleared the underlying list, the evaluated list does not change Assert.AreEqual(3, linqResultEvaluated.Count()); } [TestMethod] public void DoesNotSaveCreatingListWhenHasListTest() { var list = new List<int> {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); //list is not readonly, so we expect a new list Assert.AreNotSame(list, linqResultEvaluated); } [TestMethod] public void SavesCreatingListWhenHasReadonlyListTest() { var list = new List<int> {1, 2, 3}.AsReadOnly(); var linqResultEvaluated = list.Evaluate(); //list is readonly, so we don't expect a new list Assert.AreSame(list, linqResultEvaluated); } [TestMethod] public void SavesCreatingListWhenHasArrayTest() { var list = new[] {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); //arrays are readonly (wrt ICollection<T> interface), so we don't expect a new object Assert.AreSame(list, linqResultEvaluated); } [TestMethod] [ExpectedException(typeof (NotSupportedException))] public void CantAddToResultTest() { var list = new List<int> {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); Assert.AreNotSame(list, linqResultEvaluated); linqResultEvaluated.Add(4); } [TestMethod] [ExpectedException(typeof (NotSupportedException))] public void CantRemoveFromResultTest() { var list = new List<int> {1, 2, 3}; var linqResultEvaluated = list.Evaluate(); Assert.AreNotSame(list, linqResultEvaluated); linqResultEvaluated.Remove(1); } } 

老问题,但新的提问者在任何时候。

根据System.Linq.Enumerable的来源, ToList只是返回一个new List(source) ,而ToArray使用一个new Buffer<T>(source).ToArray()返回一个T[]

关于内存分配:

IEnumerable<T>对象上运行时, ToArrayToList多一次分配内存。 但是在大多数情况下,您不必关心它,因为GC会在需要时进行垃圾回收。

关于运行时高效:

那些质疑这个问题的人可以在你自己的机器上运行下面的代码,然后你会得到你的答案。

 class PersonC { public Guid uuid; public string name; public int age; public bool sex; public DateTime BirthDay; public double weight; } struct PersonS { public Guid uuid; public string name; public int age; public bool sex; public DateTime BirthDay; public double weight; } class PersonT<T> : IEnumerable<T> { private List<T> items; public PersonT(IEnumerable<T> init) { items = new List<T>(init); } public IEnumerator<T> GetEnumerator() => items.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => items.GetEnumerator(); } private IEnumerable<PersonC> C(int count) { for (var i = 0; i < count; ++i) { var guid = Guid.NewGuid(); var guidBytes = guid.ToByteArray(); //16 bytes yield return new PersonC { uuid = guid, name = guid.ToString(), age = guidBytes[0] ^ guidBytes[7], sex = guidBytes[14] % 2 == 0, BirthDay = DateTime.Now.AddDays(-guidBytes[11] * 18), weight = guidBytes[12] * 100 }; } } private IEnumerable<PersonS> S(int count) { for (var i = 0; i < count; ++i) { var guid = Guid.NewGuid(); var guidBytes = guid.ToByteArray(); //16 bytes yield return new PersonS { uuid = guid, name = guid.ToString(), age = guidBytes[0] ^ guidBytes[7], sex = guidBytes[14] % 2 == 0, BirthDay = DateTime.Now.AddDays(-guidBytes[11] * 18), weight = guidBytes[12] * 100 }; } } private void MakeLog(string test, List<long> log) => Console.WriteLine("{0} {1} ms -> [{2}]", test, log.Average(), string.Join(", ", log) ); private void Test1(int times, int count) { var test = Enumerable.Range(1, times).ToArray(); MakeLog("C.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = C(count).ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("C.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = C(count).ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = S(count).ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = S(count).ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); } private void Test2(int times, int count) { var test = Enumerable.Range(1, times).ToArray(); var dataC1 = new PersonT<PersonC>(C(count)); var dataS1 = new PersonT<PersonS>(S(count)); MakeLog("C1.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC1.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("C1.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC1.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S1.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS1.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S1.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS1.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); } private void Test3(int times, int count) { var test = Enumerable.Range(1, times).ToArray(); var dataC2 = (ICollection<PersonC>) new List<PersonC>(C(count)); var dataS2 = (ICollection<PersonS>) new List<PersonS>(S(count)); MakeLog("C2.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC2.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("C2.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataC2.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S2.ToList", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS2.ToList(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); MakeLog("S2.ToArray", test.Select(o => { var sw = new Stopwatch(); GC.Collect(); sw.Start(); var ret = dataS2.ToArray(); sw.Stop(); return sw.ElapsedMilliseconds; }).ToList()); } private void TestMain() { const int times = 100; const int count = 1_000_000 + 1; Test1(times, count); Test2(times, count); Test3(times, count); } 

我在我的机器上得到了这些结果:

组别1:

 C.ToList 761.79 ms -> [775, 755, 759, 759, 756, 759, 765, 750, 757, 762, 759, 754, 757, 753, 763, 753, 759, 756, 768, 754, 763, 757, 757, 777, 780, 758, 754, 758, 762, 754, 758, 757, 763, 758, 760, 754, 761, 755, 764, 847, 952, 755, 747, 763, 760, 758, 754, 763, 761, 758, 750, 764, 757, 763, 762, 756, 753, 759, 759, 757, 758, 779, 765, 760, 760, 756, 760, 756, 755, 764, 759, 753, 757, 760, 752, 764, 758, 760, 758, 760, 755, 761, 751, 753, 761, 762, 761, 758, 759, 752, 765, 756, 760, 755, 757, 753, 760, 751, 755, 779] C.ToArray 782.56 ms -> [783, 774, 771, 771, 773, 774, 775, 775, 772, 770, 771, 774, 771, 1023, 975, 772, 767, 776, 771, 779, 772, 779, 775, 771, 775, 773, 775, 771, 765, 774, 770, 781, 772, 771, 781, 762, 817, 770, 775, 779, 769, 774, 763, 775, 777, 769, 777, 772, 775, 778, 775, 771, 770, 774, 772, 769, 772, 769, 774, 775, 768, 775, 769, 774, 771, 776, 774, 773, 778, 769, 778, 767, 770, 787, 783, 779, 771, 768, 805, 780, 779, 767, 773, 771, 773, 785, 1044, 853, 775, 774, 775, 771, 770, 769, 770, 776, 770, 780, 821, 770] S.ToList 704.2 ms -> [687, 702, 709, 691, 694, 710, 696, 698, 700, 694, 701, 719, 706, 694, 702, 699, 699, 703, 704, 701, 703, 705, 697, 707, 691, 697, 707, 692, 721, 698, 695, 700, 704, 700, 701, 710, 700, 705, 697, 711, 694, 700, 695, 698, 701, 692, 696, 702, 690, 699, 708, 700, 703, 714, 701, 697, 700, 699, 694, 701, 697, 696, 699, 694, 709, 1068, 690, 706, 699, 699, 695, 708, 695, 704, 704, 700, 695, 704, 695, 696, 702, 700, 710, 708, 693, 697, 702, 694, 700, 706, 699, 695, 706, 714, 704, 700, 695, 697, 707, 704] S.ToArray 742.5 ms -> [742, 743, 733, 745, 741, 724, 738, 745, 728, 732, 740, 727, 739, 740, 726, 744, 758, 732, 744, 745, 730, 739, 738, 723, 745, 757, 729, 741, 736, 724, 744, 756, 739, 766, 737, 725, 741, 742, 736, 748, 742, 721, 746, 1043, 806, 747, 731, 727, 742, 742, 726, 738, 746, 727, 739, 743, 730, 744, 753, 741, 739, 746, 728, 740, 744, 734, 734, 738, 731, 747, 736, 731, 765, 735, 726, 740, 743, 730, 746, 742, 725, 731, 757, 734, 738, 741, 732, 747, 744, 721, 742, 741, 727, 745, 740, 730, 747, 760, 737, 740] C1.ToList 32.34 ms -> [35, 31, 31, 31, 32, 31, 31, 31, 31, 31, 31, 31, 31, 31, 33, 32, 31, 31, 31, 31, 30, 32, 31, 31, 31, 31, 32, 30, 31, 31, 31, 30, 32, 31, 31, 31, 36, 31, 31, 31, 32, 30, 31, 32, 31, 31, 31, 31, 31, 32, 31, 31, 31, 31, 33, 32, 31, 32, 31, 31, 33, 31, 31, 31, 31, 31, 32, 31, 32, 31, 34, 38, 68, 42, 79, 33, 31, 31, 31, 31, 31, 30, 30, 30, 30, 31, 31, 31, 31, 32, 31, 32, 31, 31, 31, 32, 33, 33, 31, 31] C1.ToArray 56.32 ms -> [57, 56, 59, 54, 54, 55, 56, 57, 54, 54, 55, 55, 57, 56, 59, 57, 56, 58, 56, 56, 54, 56, 57, 55, 55, 55, 57, 58, 57, 58, 55, 55, 56, 55, 57, 56, 56, 59, 56, 56, 56, 56, 58, 56, 57, 56, 56, 57, 56, 55, 56, 56, 56, 59, 56, 56, 56, 55, 55, 54, 55, 54, 57, 56, 56, 56, 55, 55, 56, 56, 56, 59, 56, 56, 57, 56, 57, 56, 56, 56, 56, 62, 55, 56, 56, 56, 69, 57, 58, 56, 57, 58, 56, 57, 56, 56, 56, 56, 56, 56] S1.ToList 88.69 ms -> [96, 90, 90, 89, 91, 88, 89, 90, 96, 89, 89, 89, 90, 90, 90, 89, 90, 90, 89, 90, 89, 91, 89, 91, 89, 91, 89, 90, 90, 89, 87, 88, 87, 88, 87, 87, 87, 87, 88, 88, 87, 87, 89, 87, 87, 87, 91, 88, 87, 86, 89, 87, 90, 89, 89, 90, 89, 87, 87, 87, 86, 87, 88, 90, 88, 87, 87, 92, 87, 87, 88, 88, 88, 86, 86, 87, 88, 87, 87, 87, 89, 87, 89, 87, 90, 89, 89, 89, 91, 89, 90, 89, 90, 88, 90, 90, 90, 88, 89, 89] S1.ToArray 143.26 ms -> [130, 129, 130, 131, 133, 130, 131, 130, 135, 137, 130, 136, 132, 131, 130, 131, 132, 130, 132, 136, 130, 131, 157, 153, 194, 364, 176, 189, 203, 194, 189, 192, 183, 140, 142, 147, 145, 134, 159, 158, 142, 167, 130, 143, 145, 144, 160, 154, 156, 153, 153, 164, 142, 145, 137, 134, 145, 143, 142, 135, 133, 133, 135, 134, 134, 139, 139, 133, 134, 141, 133, 132, 133, 132, 133, 131, 135, 132, 133, 132, 128, 128, 130, 132, 129, 129, 129, 129, 129, 128, 134, 129, 129, 129, 129, 128, 128, 137, 130, 131] C2.ToList 3.25 ms -> [5, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3] C2.ToArray 3.37 ms -> [4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 5, 4, 9, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 4, 3, 3, 4, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 3, 4, 4, 3, 3, 4, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 4, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3] S2.ToList 37.72 ms -> [38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 40, 38, 38, 39, 39, 38, 38, 38, 38, 37, 37, 37, 37, 39, 37, 37, 39, 38, 37, 37, 37, 37, 39, 38, 37, 37, 38, 37, 38, 37, 37, 38, 37, 37, 37, 38, 37, 37, 36, 37, 38, 37, 39, 37, 39, 38, 37, 38, 38, 38, 38, 38, 38, 37, 38, 38, 38, 38, 38, 37, 38, 37, 37, 38, 37, 37, 39, 41, 37, 38, 38, 37, 37, 37, 37, 38, 37, 37, 37, 40, 37, 37, 37, 37, 39, 38] S2.ToArray 38.86 ms -> [39, 37, 39, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 38, 39, 38, 38, 38, 38, 38, 38, 38, 38, 39, 39, 38, 38, 38, 39, 37, 38, 38, 38, 38, 38, 37, 37, 38, 37, 37, 38, 38, 40, 38, 38, 38, 38, 38, 39, 38, 38, 39, 38, 38, 39, 38, 38, 40, 38, 39, 38, 38, 39, 38, 38, 38, 38, 38, 39, 38, 38, 38, 39, 39, 37, 38, 38, 39, 71, 78, 37, 37, 37, 39, 38, 38, 39, 38, 38, 38, 38, 38, 39, 38, 38, 38, 39, 38, 38, 38] 

Group2:

 C.ToList 756.81 ms C.ToArray 774.21 ms S.ToList 709.7 ms S.ToArray 753.51 ms C1.ToList 32.06 ms C1.ToArray 56.58 ms S1.ToList 89.43 ms S1.ToArray 132.85 ms C2.ToList 3.45 ms C2.ToArray 3.36 ms S2.ToList 41.43 ms S2.ToArray 40.84 ms 

Group3:

 C.ToList 756.64 ms C.ToArray 771.56 ms S.ToList 705.42 ms S.ToArray 749.59 ms C1.ToList 31.45 ms C1.ToArray 57.03 ms S1.ToList 91.26 ms S1.ToArray 129.77 ms C2.ToList 3.26 ms C2.ToArray 3.29 ms S2.ToList 41.57 ms S2.ToArray 40.69 ms 

Group4:

 C.ToList 729.65 ms -> [749, 730, 721, 719, 723, 743, 721, 724, 727, 722, 716, 725, 723, 726, 718, 722, 731, 722, 723, 725, 723, 722, 728, 726, 728, 718, 726, 1088, 788, 737, 729, 710, 730, 728, 717, 723, 728, 721, 722, 728, 722, 736, 723, 729, 732, 724, 726, 727, 728, 728, 726, 726, 725, 727, 725, 728, 728, 718, 724, 725, 726, 724, 726, 729, 727, 722, 722, 725, 725, 728, 724, 727, 738, 717, 726, 723, 725, 725, 727, 724, 720, 726, 726, 723, 727, 730, 723, 721, 725, 727, 727, 733, 720, 722, 722, 725, 722, 725, 728, 726] C.ToArray 788.36 ms -> [748, 740, 742, 797, 1090, 774, 781, 787, 784, 786, 786, 782, 781, 781, 784, 783, 783, 781, 783, 787, 783, 784, 775, 789, 784, 785, 778, 774, 781, 783, 786, 781, 780, 788, 778, 785, 777, 781, 786, 782, 781, 787, 782, 787, 784, 773, 783, 782, 781, 777, 783, 781, 785, 788, 777, 776, 784, 784, 783, 789, 778, 781, 791, 768, 779, 783, 781, 787, 786, 781, 784, 781, 785, 781, 780, 809, 1155, 780, 790, 789, 783, 776, 785, 783, 786, 787, 782, 782, 787, 777, 779, 784, 783, 776, 786, 775, 782, 779, 784, 784] S.ToList 705.54 ms -> [690, 705, 709, 708, 702, 707, 703, 696, 703, 702, 700, 703, 700, 707, 705, 699, 697, 703, 695, 698, 707, 697, 711, 710, 699, 700, 708, 707, 693, 710, 704, 691, 702, 700, 703, 700, 705, 700, 703, 695, 709, 705, 698, 699, 709, 700, 699, 704, 691, 705, 703, 700, 708, 1048, 710, 706, 706, 692, 702, 705, 695, 701, 710, 697, 698, 706, 705, 707, 707, 695, 698, 704, 698, 699, 705, 698, 703, 702, 701, 697, 702, 702, 704, 703, 699, 707, 703, 705, 701, 717, 698, 695, 713, 696, 708, 705, 697, 699, 700, 698] S.ToArray 745.01 ms -> [751, 743, 727, 734, 736, 745, 739, 750, 739, 750, 758, 739, 744, 738, 730, 744, 745, 739, 744, 750, 733, 735, 743, 731, 749, 748, 727, 746, 749, 731, 737, 803, 1059, 756, 769, 748, 740, 745, 741, 746, 749, 732, 741, 742, 732, 744, 746, 737, 742, 739, 733, 744, 741, 729, 746, 760, 725, 741, 764, 739, 750, 751, 727, 745, 738, 727, 735, 741, 720, 736, 740, 733, 741, 746, 731, 749, 756, 740, 738, 736, 732, 741, 741, 733, 741, 744, 736, 742, 742, 735, 743, 746, 729, 748, 765, 743, 734, 742, 728, 749] C1.ToList 32.27 ms -> [36, 31, 31, 32, 31, 32, 31, 30, 32, 30, 30, 30, 34, 32, 31, 31, 31, 31, 31, 31, 31, 32, 38, 51, 68, 57, 35, 30, 31, 31, 30, 30, 33, 30, 31, 34, 31, 34, 32, 31, 31, 31, 31, 32, 30, 30, 31, 30, 31, 31, 32, 31, 31, 31, 32, 31, 31, 31, 32, 31, 33, 31, 31, 32, 30, 30, 30, 30, 30, 33, 30, 33, 32, 31, 30, 31, 31, 32, 32, 31, 35, 31, 34, 31, 31, 32, 31, 31, 32, 31, 32, 31, 31, 35, 31, 31, 31, 31, 31, 32] C1.ToArray 56.72 ms -> [58, 56, 57, 57, 59, 58, 58, 57, 56, 59, 57, 55, 55, 54, 56, 55, 56, 56, 57, 59, 56, 55, 58, 56, 55, 55, 55, 55, 58, 58, 55, 57, 57, 56, 57, 57, 57, 57, 59, 59, 56, 57, 56, 57, 57, 56, 57, 59, 58, 56, 57, 57, 57, 58, 56, 56, 59, 56, 59, 57, 57, 57, 57, 59, 57, 56, 57, 56, 58, 56, 57, 56, 57, 59, 55, 58, 55, 55, 56, 56, 56, 56, 56, 56, 56, 56, 56, 57, 56, 56, 57, 56, 56, 57, 58, 57, 57, 57, 57, 57] S1.ToList 90.72 ms -> [95, 90, 90, 89, 89, 89, 91, 89, 89, 87, 91, 89, 89, 89, 91, 89, 89, 89, 90, 89, 89, 90, 88, 89, 88, 90, 89, 90, 89, 89, 90, 90, 89, 89, 90, 91, 89, 91, 89, 90, 89, 89, 90, 91, 89, 89, 89, 89, 89, 89, 90, 89, 89, 89, 90, 89, 90, 89, 91, 89, 90, 89, 90, 89, 90, 89, 96, 89, 90, 89, 89, 89, 89, 89, 90, 89, 89, 89, 90, 87, 89, 90, 90, 91, 89, 91, 89, 89, 90, 91, 90, 89, 93, 144, 149, 90, 90, 89, 89, 89] S1.ToArray 131.4 ms -> [130, 128, 127, 134, 129, 129, 130, 136, 131, 130, 132, 132, 133, 131, 132, 131, 133, 132, 130, 131, 132, 131, 130, 133, 133, 130, 130, 131, 131, 131, 132, 134, 131, 131, 132, 131, 132, 131, 134, 131, 131, 130, 131, 131, 130, 132, 129, 131, 131, 131, 132, 131, 133, 134, 131, 131, 132, 132, 131, 133, 131, 131, 130, 133, 131, 130, 134, 132, 131, 132, 132, 131, 131, 134, 131, 131, 132, 132, 131, 130, 138, 130, 130, 131, 132, 132, 130, 134, 131, 131, 132, 131, 130, 132, 133, 131, 131, 131, 130, 131] C2.ToList 3.21 ms -> [4, 3, 3, 3, 4, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3] C2.ToArray 3.22 ms -> [4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4] S2.ToList 41.46 ms -> [42, 40, 41, 40, 42, 40, 40, 40, 40, 40, 40, 40, 40, 41, 40, 40, 41, 40, 40, 40, 39, 41, 41, 39, 40, 40, 43, 40, 39, 40, 40, 40, 40, 40, 40, 41, 40, 40, 40, 43, 40, 43, 75, 76, 47, 39, 40, 40, 40, 40, 42, 40, 41, 40, 40, 40, 44, 41, 40, 42, 42, 40, 41, 41, 41, 41, 41, 40, 41, 41, 41, 41, 42, 41, 40, 41, 41, 42, 42, 41, 40, 41, 41, 41, 41, 41, 40, 42, 40, 42, 41, 41, 41, 43, 41, 41, 41, 41, 42, 41] S2.ToArray 41.14 ms -> [42, 41, 41, 40, 40, 40, 40, 41, 41, 42, 41, 42, 41, 41, 41, 42, 41, 41, 42, 41, 41, 41, 41, 41, 42, 40, 41, 40, 42, 40, 42, 41, 40, 42, 41, 41, 43, 42, 41, 41, 41, 41, 41, 41, 41, 41, 41, 41, 40, 40, 41, 41, 41, 40, 42, 41, 41, 41, 41, 41, 40, 41, 41, 42, 41, 41, 41, 42, 41, 41, 41, 41, 41, 41, 42, 42, 42, 41, 45, 46, 41, 40, 41, 41, 42, 41, 41, 41, 41, 41, 41, 40, 41, 43, 40, 40, 40, 40, 43, 41] 

Group5:

 C.ToList 757.06 ms -> [770, 752, 752, 751, 778, 763, 761, 763, 747, 758, 748, 747, 754, 749, 752, 753, 756, 762, 750, 753, 756, 749, 755, 757, 755, 756, 755, 744, 753, 758, 747, 751, 759, 751, 761, 755, 746, 752, 752, 749, 746, 752, 753, 755, 752, 755, 754, 754, 966, 937, 749, 759, 748, 747, 754, 749, 755, 750, 746, 754, 757, 752, 753, 745, 758, 755, 761, 753, 751, 755, 755, 752, 746, 756, 755, 746, 742, 751, 751, 749, 752, 751, 756, 756, 755, 742, 749, 754, 749, 756, 753, 751, 754, 752, 751, 754, 753, 749, 755, 756] C.ToArray 772.8 ms -> [766, 772, 755, 763, 758, 767, 763, 762, 761, 768, 769, 763, 770, 757, 765, 760, 766, 759, 764, 761, 760, 777, 1102, 881, 759, 765, 758, 762, 772, 761, 758, 757, 765, 769, 769, 761, 762, 762, 763, 760, 770, 764, 760, 768, 758, 766, 763, 770, 769, 761, 764, 761, 761, 767, 761, 762, 764, 757, 765, 766, 767, 771, 753, 762, 769, 768, 759, 764, 764, 760, 763, 763, 763, 763, 763, 767, 761, 771, 760, 765, 760, 758, 768, 770, 751, 771, 767, 771, 765, 763, 760, 765, 765, 769, 767, 767, 1193, 774, 767, 764] S.ToList 704.73 ms -> [682, 708, 705, 699, 705, 704, 695, 703, 702, 699, 701, 708, 699, 702, 703, 701, 701, 699, 701, 707, 707, 700, 701, 705, 700, 697, 706, 702, 701, 706, 699, 692, 702, 697, 707, 704, 697, 698, 699, 699, 702, 703, 698, 697, 702, 703, 702, 704, 694, 697, 707, 695, 711, 710, 700, 693, 703, 699, 699, 706, 698, 701, 703, 704, 698, 706, 700, 704, 701, 699, 702, 705, 694, 698, 709, 736, 1053, 704, 694, 700, 698, 696, 701, 700, 700, 706, 706, 692, 698, 707, 703, 695, 703, 699, 694, 708, 695, 694, 706, 695] S.ToArray 744.17 ms -> [746, 740, 725, 740, 739, 731, 746, 760, 735, 738, 740, 734, 744, 748, 737, 744, 745, 727, 736, 738, 728, 743, 745, 735, 748, 760, 739, 748, 762, 742, 741, 747, 733, 746, 758, 742, 742, 741, 724, 744, 747, 727, 740, 740, 729, 742, 757, 741, 740, 742, 726, 739, 746, 1133, 749, 737, 730, 740, 747, 733, 747, 752, 731, 747, 742, 730, 741, 749, 731, 749, 743, 730, 747, 742, 731, 737, 745, 734, 739, 735, 727, 743, 752, 731, 744, 742, 729, 740, 746, 731, 739, 746, 733, 745, 743, 733, 739, 742, 727, 737] C1.ToList 31.71 ms -> [35, 32, 32, 30, 31, 33, 31, 32, 32, 31, 31, 32, 32, 33, 32, 31, 31, 32, 31, 32, 32, 32, 31, 32, 33, 32, 31, 31, 31, 32, 31, 34, 31, 31, 32, 33, 32, 32, 31, 32, 34, 32, 31, 32, 33, 31, 32, 32, 31, 32, 32, 32, 32, 32, 32, 31, 31, 32, 31, 33, 30, 31, 32, 30, 30, 33, 32, 32, 34, 31, 31, 31, 31, 32, 31, 31, 31, 31, 32, 31, 31, 33, 31, 32, 32, 32, 33, 32, 31, 31, 31, 31, 31, 32, 32, 33, 32, 31, 31, 32] C1.ToArray 59.53 ms -> [63, 57, 58, 58, 57, 59, 59, 57, 60, 131, 127, 67, 58, 56, 59, 56, 57, 58, 58, 58, 57, 59, 60, 57, 57, 59, 60, 57, 57, 57, 58, 58, 58, 58, 57, 57, 61, 57, 58, 57, 57, 57, 57, 57, 58, 58, 58, 58, 57, 58, 59, 57, 58, 57, 57, 59, 58, 58, 59, 57, 59, 57, 56, 56, 59, 56, 56, 59, 57, 58, 58, 58, 57, 58, 59, 59, 58, 57, 58, 62, 65, 57, 57, 57, 58, 60, 59, 58, 59, 57, 58, 57, 58, 59, 58, 58, 58, 59, 60, 58] S1.ToList 82.78 ms -> [87, 82, 83, 83, 82, 82, 83, 84, 82, 83, 84, 84, 84, 82, 82, 84, 82, 84, 83, 84, 82, 82, 82, 81, 83, 83, 83, 84, 84, 82, 82, 83, 83, 83, 82, 83, 85, 83, 82, 82, 84, 82, 82, 83, 83, 83, 82, 82, 82, 83, 82, 83, 82, 84, 82, 83, 82, 83, 82, 82, 82, 84, 82, 83, 82, 82, 86, 83, 83, 82, 83, 83, 83, 82, 84, 82, 83, 81, 82, 82, 82, 82, 83, 83, 83, 82, 83, 84, 83, 82, 83, 83, 83, 82, 83, 84, 82, 82, 83, 83] S1.ToArray 122.3 ms -> [122, 119, 119, 120, 119, 120, 120, 121, 119, 119, 122, 120, 120, 120, 122, 120, 123, 120, 120, 120, 121, 123, 120, 120, 120, 121, 120, 121, 122, 120, 123, 119, 121, 118, 121, 120, 120, 120, 119, 124, 119, 121, 119, 120, 120, 120, 120, 120, 122, 121, 123, 230, 203, 123, 119, 119, 122, 119, 120, 120, 120, 122, 120, 121, 120, 121, 120, 121, 120, 121, 120, 120, 120, 121, 122, 121, 123, 119, 119, 119, 119, 121, 120, 120, 120, 122, 121, 122, 119, 120, 120, 121, 121, 120, 121, 120, 121, 118, 118, 118] C2.ToList 3.43 ms -> [5, 3, 4, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 4, 3, 4, 4, 3, 3, 3, 3, 4, 3, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 6, 4, 4, 3, 3, 4, 3, 3, 4, 3, 3, 3, 3, 3, 3, 3, 4, 3, 3, 3, 3, 3, 3, 4, 3, 4, 4, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 4, 3, 3, 3, 4, 4, 3, 3, 3, 3] C2.ToArray 3.48 ms -> [3, 3, 3, 3, 4, 4, 3, 4, 4, 4, 3, 4, 3, 3, 4, 3, 3, 4, 3, 4, 3, 3, 3, 4, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 3, 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, 3, 4, 3, 3, 4, 3, 3, 4, 3, 3, 4, 4, 3, 3, 4, 3, 4, 4, 3, 4, 4, 4, 4, 4, 3, 3, 3, 4, 4, 3, 4, 4, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 4, 4, 4, 4, 3] S2.ToList 41.47 ms -> [41, 41, 49, 67, 82, 41, 41, 40, 40, 40, 40, 40, 41, 40, 40, 40, 40, 40, 41, 40, 42, 42, 40, 40, 41, 41, 41, 40, 41, 40, 41, 40, 41, 40, 42, 41, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, 42, 41, 41, 41, 42, 40, 41, 40, 40, 40, 42, 40, 41, 42, 41, 42, 41, 42, 40, 41, 41, 41, 41, 41, 41, 41, 41, 40, 41, 40, 41, 41, 41, 40, 41, 41, 40, 40, 41, 41, 41, 41, 41, 43, 40, 40, 41, 42, 41] S2.ToArray 40.62 ms -> [42, 41, 44, 40, 40, 40, 40, 41, 41, 40, 41, 41, 41, 40, 41, 41, 40, 41, 41, 40, 41, 40, 40, 41, 42, 41, 41, 41, 40, 40, 40, 40, 40, 41, 41, 42, 40, 41, 41, 41, 41, 41, 40, 42, 40, 40, 41, 41, 41, 40, 41, 40, 40, 40, 40, 40, 41, 40, 40, 41, 40, 40, 40, 40, 41, 40, 41, 41, 41, 40, 41, 41, 40, 41, 40, 41, 42, 40, 41, 41, 42, 41, 41, 40, 41, 40, 41, 40, 41, 41, 40, 40, 40, 41, 41, 40, 40, 40, 40, 40] 

Due to stackoverflow's limit to the characters amount of the answer, the sample lists of Group2 and Group3 are omitted.

As you can see, it's really not important to use ToList or ToArry in most cases.

While processing runtime-calculated IEnumerable<T> objects, if the load brought by calculation is heavy than memory allocation and copy operations of ToList and ToArray , the disparity is insignificant ( C.ToList vs C.ToArray and S.ToList vs S.ToArray ).

The difference can be observed only on non-runtime-calculated IEnumerable<T> only objects ( C1.ToList vs C1.ToArray and S1.ToList vs S1.ToArray ). But the absolute difference (<60ms) is still acceptable on an one million small object IEnumerable<T> . In fact, the difference is decided by the implementation of Enumerator<T> of IEnumerable<T> . So, if your program is really really really sensitive on this, you do have to profile, profile, profile ! At last you'll probably find that the bottleneck is not on ToList or ToArray , but the detail of enumerators.

And, the result of C2.ToList vs C2.ToArray and S2.ToList vs S2.ToArray shows that, you really don't need to care ToList or ToArray on non-runtime-calculated ICollection<T> objects.

Of course, this is just results on my machine, the actual time spend of these operations on different machine will not be the same, you can find out on your machine using code above.

The only reason you need to make a choice is that, you have specific needs on List<T> or T[] , as described by the answer of @Jeppe Stig Nielsen .

For anyone interested in using this result in another Linq-to-sql such as

 from q in context.MyTable where myListOrArray.Contains(q.someID) select q; 

then the SQL that is generated is the same whether you used a List or Array for the myListOrArray. Now I know some may ask why even enumerate before this statement, but there is a difference between the SQL generated from an IQueryable vs (List or Array).

I found the other benchmarks people have done here lacking, so here's my crack at it. Let me know if you find something wrong with my methodology.

 /* This is a benchmarking template I use in LINQPad when I want to do a * quick performance test. Just give it a couple of actions to test and * it will give you a pretty good idea of how long they take compared * to one another. It's not perfect: You can expect a 3% error margin * under ideal circumstances. But if you're not going to improve * performance by more than 3%, you probably don't care anyway.*/ void Main() { // Enter setup code here var values = Enumerable.Range(1, 100000) .Select(i => i.ToString()) .ToArray() .Select(i => i); values.GetType().Dump(); var actions = new[] { new TimedAction("ToList", () => { values.ToList(); }), new TimedAction("ToArray", () => { values.ToArray(); }), new TimedAction("Control", () => { foreach (var element in values) { // do nothing } }), // Add tests as desired }; const int TimesToRun = 1000; // Tweak this as necessary TimeActions(TimesToRun, actions); } #region timer helper methods // Define other methods and classes here public void TimeActions(int iterations, params TimedAction[] actions) { Stopwatch s = new Stopwatch(); int length = actions.Length; var results = new ActionResult[actions.Length]; // Perform the actions in their initial order. for (int i = 0; i < length; i++) { var action = actions[i]; var result = results[i] = new ActionResult { Message = action.Message }; // Do a dry run to get things ramped up/cached result.DryRun1 = s.Time(action.Action, 10); result.FullRun1 = s.Time(action.Action, iterations); } // Perform the actions in reverse order. for (int i = length - 1; i >= 0; i--) { var action = actions[i]; var result = results[i]; // Do a dry run to get things ramped up/cached result.DryRun2 = s.Time(action.Action, 10); result.FullRun2 = s.Time(action.Action, iterations); } results.Dump(); } public class ActionResult { public string Message { get; set; } public double DryRun1 { get; set; } public double DryRun2 { get; set; } public double FullRun1 { get; set; } public double FullRun2 { get; set; } } public class TimedAction { public TimedAction(string message, Action action) { Message = message; Action = action; } public string Message { get; private set; } public Action Action { get; private set; } } public static class StopwatchExtensions { public static double Time(this Stopwatch sw, Action action, int iterations) { sw.Restart(); for (int i = 0; i < iterations; i++) { action(); } sw.Stop(); return sw.Elapsed.TotalMilliseconds; } } #endregion 

You can download the LINQPad Script here .

结果: ToArray vs ToList performance

Tweaking the code above, you will discover that:

  1. The difference is less significant when dealing with smaller arrays . More iterations, but smaller arrays
  2. The difference is less significant when dealing with int s rather than string s.
  3. Using large struct s instead of string s takes a lot more time generally, but doesn't really change the ratio much.

This agrees with the conclusions of the top-voted answers:

  1. You're unlikely to notice a performance difference unless your code is frequently producing many large lists of data. (There was only a 200ms difference when creating 1000 lists of 100K strings apiece.)
  2. ToList() consistently runs faster, and would be a better choice if you're not planning to hang on to the results for a long time.

更新

@JonHanna pointed out that depending on the implementation of Select it's possible for a ToList() or ToArray() implementation to predict the resulting collection's size ahead of time. Replacing .Select(i => i) in the code above with Where(i => true) yields very similar results at the moment, and is more likely to do so regardless of the .NET implementation.

Benchmark using Where instead of Select