当list1
和list2
中的项目顺序可能不同时
list2 = list1.ToList()
并且都属于List
类型
答案 0 :(得分:2)
如果list1
的排序方式一致,那么list2
将采用相同的顺序。
有可能list1
是某种类型,它本身并不承诺每次枚举时都有相同的顺序,在这种情况下,两者可能会有所不同,但它是list1
的枚举逻辑对此负责,而不是ToList()
。 (list1
的名称表明它本身就是一个列表,在这种情况下,订单肯定会是相同的。)
这里的一个答案已经包含了ToList()
的一个实现的来源。它不是唯一存在的ToList()
版本,并且corefx优化了比netfx更多的情况,但仍然是所有版本按照它们在枚举时提供它们的顺序生成列表。
另一个答案是文档中没有保证这一点,只能通过List<T>
构造函数的重载描述来进行枚举(顺便说一下,ToList()
的所有实现都使用的唯一构造函数。 1}}在所有情况下)。
但是,不会接受不承诺维持订单的ToList()
更改。
考虑someSource.OrderBy(x => x.ID).ToList()
的情况。在这种情况下(顺便提一下,是在corefx中优化的情况),如果ToList()
可以更改顺序,则显然会删除OrderBy()
的点。
好的,那么如果有人以一种不承诺维持秩序的方式改变了ToList()
,又将OrderBy()
视为特例呢? (毕竟,在一个版本中,由于性能原因,它已经是一个特例)。好吧,那仍然会说someSource.OrderBy(x => x.ID).Where(x => !x.Deleted).ToList()
。总而言之,如果我们的ToList()
版本没有维护顺序,我们就能够提出某种linq查询,其中查询的另一部分承诺给定订单ToList()
的这种实现打破了整个查询的承诺。
因此,除非使用ParallelEnumerable
,否则除非您使用AsOrdered()
,否则禁止使用特殊套管来明确不承诺维护订单(ToList()
,因为它有许多优点除非在并行处理方面确实有必要,否则不能维护订单)我们无法在不违反整个linq查询承诺的情况下对ToList()
进行更改而不维护订单。
因此虽然{Server:nginx.access.remote.count(1m,{Server:nginx.access.remote.last()},eq)}>10000
的文档中没有提及保证,但它仍然有保证,不会在以后的版本中更改。
答案 1 :(得分:1)
简单的答案是否定的,ToList
将循环遍历可枚举的源并保持相同的顺序。 List<T>
保证订单,因此在其上调用ToList
不会改变它。
然而,更细致的答案是,您可能不会以List<T>
开头,并且可能会更加一般IEnumerable<T>
,但根本不保证订单。这意味着多次调用{{1} } 可能产生不同的输出。
但实际上,source.ToList()
的所有实现都会保留顺序。
答案 2 :(得分:1)
对于初学者:可以说每个人都希望这样做。但为什么呢?
根据文档,采用List<T>
的{{1}}构造函数保证订单被保留:
元素按照集合枚举器读取的顺序复制到List上。
虽然IEnumerable<T>
的文档没有做出这样的承诺(尽管如此,并没有说任何相反的事情)。
在内部,一个使用另一个,因此您是安全的,但如果.ToList()
的内部实施发生变化,则无法保证您的安全。因此,如果您想确定,请直接致电.ToList()
。
Smallprint:如果你对它很挑剔......我找不到保证new List(oldList);
接口按顺序返回列表的元素。所以两种方式,你必须看看是什么,如果你需要依赖它,也许可以编写一些单元测试来断言这种行为,这样你就可以在当前行为发生变化时立即得到通知。
答案 3 :(得分:1)
一般答案是否,即使两个列表都是List
的类型,也不会保留订单。
因为List
不是密封类。另一个类可以从它派生并覆盖GetEnumerable
并可能无序地返回项目。
听起来很奇怪,是的。但它可能。所以你不能说ToList将返回完全相同的列表,除非它们都是List
的具体类型而不是任何派生类型。
另一个答案是它的实施细节可能在未来发生变化。我不这么认为。列表是.net集合中非常重要的一部分。这种无法改变的突破性变化非常不可取。
别担心,只要你使用具体的List
订单始终保留。
答案 4 :(得分:0)
应该没有什么不同。检查源代码。
public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
if (source == null) throw Error.ArgumentNull("source");
return new List<TSource>(source);
}
创建列表时的部分
// Constructs a List, copying the contents of the given collection. The
// size and capacity of the new list will both be equal to the size of the
// given collection.
//
public List(IEnumerable<T> collection) {
if (collection==null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
Contract.EndContractBlock();
ICollection<T> c = collection as ICollection<T>;
if( c != null) {
int count = c.Count;
if (count == 0)
{
_items = _emptyArray;
}
else {
_items = new T[count];
c.CopyTo(_items, 0);
_size = count;
}
}
else {
_size = 0;
_items = _emptyArray;
// This enumerable could be empty. Let Add allocate a new array, if needed.
// Note it will also go to _defaultCapacity first, not 1, then 2, etc.
using(IEnumerator<T> en = collection.GetEnumerator()) {
while(en.MoveNext()) {
Add(en.Current);
}
}
}
}
https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs