我试图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()
由枚举给一个指针代替.
这里发生了什么?
不同之处在于,一个是可以产生一组Parent
对象的表达式,另一个是Parent
对象列表.
每次使用表达式时,它都将使用原始结果DoOtherStuff
,然后对它们进行排序.在你的情况下,它意味着它将创建一组新的Parent
对象(因为它们显然不会保留以前使用的子对象).
这意味着当您遍历对象并对子项进行排序时,这些对象将被丢弃.当您再次使用表达式返回结果时,它将创建一组新的对象,其中子项自然是原始顺序.