在foreach中列出<T> vs IEnumerable <T>

wly*_*les 5 c# linq foreach

我试图OrderBy在foreach循环中使用一些列表进行排序,但由于某种原因,他们没有在循环之外维护它们的排序顺序.以下是一些简化的代码和注释,以突出显示正在发生的事情:

public class Parent
{
    // Other properties...
    public IList<Child> Children { get; set; }
}

public IEnumerable<Parent> DoStuff()
{
    var result = DoOtherStuff() // Returns IEnumerable<Parent>
        .OrderByDescending(SomePredicate) 
        .ThenBy(AnotherPredicate); // This sorting works as expected in the return value.

    foreach (Parent parent in result)
    {
        parent.Children = parent.Children.OrderBy(YetAnotherPredicate).ToList();
        // When I look at parent.Children here in the debugger, it's sorted properly.
    }

    return result;
    // When I look at the return value, the Children are not sorted.
}
Run Code Online (Sandbox Code Playgroud)

但是,当我改为这样指定result:

var result = DoOtherStuff()
    .OrderByDescending(SomePredicate)
    .ThenBy(AnotherPredicate)
    .ToList(); // <-- Added ToList here
Run Code Online (Sandbox Code Playgroud)

然后返回值让孩子们在每个父母中正确排序.

foreach循环中List<T>vs IEnumerable<T>a 的行为是什么?

似乎存在某种差异,因为将结果转换为List修复了foreach循环中排序的问题.这感觉就像第一代码片段创建一个迭代器,使每个元素的副本,当你用foreach迭代(因此我的更改都会应用到副本而不是原始对象result),而使用ToList()由枚举给一个指针代替.

这里发生了什么?

Guf*_*ffa 7

不同之处在于,一个是可以产生一组Parent对象的表达式,另一个是Parent对象列表.

每次使用表达式时,它都将使用原始结果DoOtherStuff,然后对它们进行排序.在你的情况下,它意味着它将创建一组新的Parent对象(因为它们显然不会保留以前使用的子对象).

这意味着当您遍历对象并对子项进行排序时,这些对象将被丢弃.当您再次使用表达式返回结果时,它将创建一组新的对象,其中子项自然是原始顺序.