C# ToList()可以更改列表中项目的顺序吗?

C# ToList()可以更改列表中项目的顺序吗?,c#,list,C#,List,当 list2=list1.ToList()和两者都属于List?类型,应该没有什么不同。检查源代码 public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { if (source == null) throw Error.ArgumentNull("source"); return new List<TSource>(source



list2=list1.ToList()
和两者都属于
List

类型,应该没有什么不同。检查源代码

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    return new List<TSource>(source);
}
公共静态列表列表(此IEnumerable源代码){
if(source==null)抛出错误.ArgumentNull(“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);                                    
                }
            }
        }
    }
//构造一个列表,复制给定集合的内容。这个
//新列表的大小和容量都将等于
//给定集合。
// 
公共列表(IEnumerable集合){
if(集合==null)
ThrowHelper.ThrowArgumentNullException(argument.collection除外);
Contract.EndContractBlock();
ICollection c=作为ICollection的集合;
如果(c!=null){
int计数=c计数;
如果(计数=0)
{
_项目=_emptyArray;
}
否则{
_项目=新的T[计数];
c、 复制到(_项,0);
_大小=计数;
}
}    
否则{
_尺寸=0;
_项目=_emptyArray;
//此可枚举项可能为空。如果需要,让Add分配一个新数组。
//注意,它也将首先转到_defaultCapacity,而不是1,然后是2,以此类推。
使用(IEnumerator en=collection.GetEnumerator()){
while(en.MoveNext()){
添加(当前版本);
}
}
}
}

简单的答案是否定的,
ToList
只会在源枚举上循环,并保持相同的顺序<代码>列表保证了顺序,因此对其调用
ToList
不会改变顺序

然而,更微妙的回答是,您可能不是从
列表开始的,可能有一个更通用的
IEnumerable
,它根本不能保证顺序。这意味着对
source.ToList()
的多个调用可能会产生不同的输出


然而在实践中,几乎所有IEnumerable的实现都将保持秩序。

首先:可以肯定地说,每个人都期望这样。但是为什么呢

根据文档,采用
IEnumerable
List
的构造函数保证了顺序的保留:

元素被复制到列表中的顺序与集合的枚举器读取的顺序相同

.ToList()
的文档没有做出这样的承诺(不过也没有说任何相反的话)

在内部,一个使用另一个,因此您是安全的,但是如果
.ToList()
的内部实现发生更改,则不能保证您是安全的。所以如果你想确定,你应该调用
newlist(oldList)直接


如果你对它吹毛求疵。。。我无法保证
IEnumerable
接口也会按顺序返回列表中的元素。因此,从这两个方面来看,您都必须了解是什么,如果您需要依赖它,可以编写一些单元测试来断言此行为,以便在当前行为发生变化时立即得到通知。

如果
list1
的顺序一致,则
list2
的顺序将相同

list1
可能是某种类型,它本身并不保证每次枚举时都具有相同的顺序,在这种情况下,两者当然可能有所不同,但造成这种情况的是
list1
的枚举逻辑,而不是
ToList()
。(列表1的名称表明它本身就是一个列表,在这种情况下,顺序肯定是相同的)

这里的一个答案已经包括
ToList()
的一个实现的源代码。它不是唯一存在的
ToList()
版本,corefx优化的情况比netfx多得多,但所有版本生成列表的顺序与源代码在枚举时提供列表的顺序相同

另一个答案是,文档中并没有保证这一点,只是描述了采用枚举的
列表
构造函数的重载(顺便说一句,它不是所有情况下
ToList()
的所有实现都使用的唯一构造函数)

但是,如果更改为
ToList()
,但未承诺维持订单,则不会被接受

考虑
someSource.OrderBy(x=>x.ID).ToList()的情况。在这种情况下(顺便说一句,这是corefx中优化的情况),如果
ToList()
可以更改顺序,则显然会删除
OrderBy()的点

好的,那么如果有人改变了
ToList()
,而不是承诺维持秩序,而是将
OrderBy()
视为特例,该怎么办?(毕竟,在一个版本中,出于性能原因,这已经是一个特例)。好的,这仍然会破坏say
someSource.OrderBy(x=>x.ID).Where(x=>!x.Deleted).ToList()
。总之,如果我们有一个版本的
ToList()
没有维护顺序,我们就能够提出某种linq查询,其中一个给定的顺序是由查询的另一部分承诺的,而
ToList()
的这种实现破坏了整个查询的承诺

因此,除非使用特殊的大小写,否则一个明确不承诺维护顺序的源(
ParallelEnumerable
不承诺,除非您使用
AsOrdered()
,因为除非在并行处理中确实需要,否则不维护顺序有很多好处)我们无法对
ToList()进行更改
无法维持秩序