列表< T>与IEnumerable T在foreach中 [英] List<T> vs IEnumerable<T> in foreach

查看:57
本文介绍了列表< T>与IEnumerable T在foreach中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.
}

但是,当我改为这样分配result时:

var result = DoOtherStuff()
    .OrderByDescending(SomePredicate)
    .ThenBy(AnotherPredicate)
    .ToList(); // <-- Added ToList here

然后返回值将子级在每个父级中正确排序.

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

似乎存在某种差异,因为将结果转换为List可以解决foreach循环中排序的问题.像第一个代码片段一样,它感觉,它创建了一个迭代器,该迭代器在使用foreach进行迭代时会为每个元素创建一个副本(因此,我的更改将应用​​于副本,但不会应用于result中的原始对象),而使用ToList()时,枚举器将改为提供一个指针.

这是怎么回事?

解决方案

区别在于,一个是可以生成一组Parent对象的表达式,而另一个是可以列出Parent对象的列表.

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

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

I was trying to get some Lists sorted using OrderBy within a foreach loop, but for some reason they weren't maintaining their sort order outside of the loop. Here's some simplified code and comments to highlight what was happening:

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.
}

However, when I instead assign result like this:

var result = DoOtherStuff()
    .OrderByDescending(SomePredicate)
    .ThenBy(AnotherPredicate)
    .ToList(); // <-- Added ToList here

then the return value has the Children sorted properly in each of the Parents.

What is the behavior of List<T> vs an IEnumerable<T> in a foreach loop?

There seems to be some sort of difference since turning result into a List fixed the problems with sorting in the foreach loop. It feels like the first code snippet creates an iterator that makes a copy of each element when you do the iteration with foreach (and thus my changes get applied to the copy but not the original object in result), while using ToList() made the enumerator give a pointer instead.

What's going on here?

解决方案

The difference is that one is an expression that can procuce a set of Parent objects, and the other is a list of Parent objects.

Each time that you use the expression, it will use the original result from DoOtherStuff and then sort them. In your case it means that it will create a new set of Parent objects (as they obviously don't retain the children from the previous use).

This means that when you loop through the objects and sort the children, those objects will be thrown away. When you use the expression again to return the result, it will create a new set of objects where the children naturally is in the original order.

这篇关于列表&lt; T&gt;与IEnumerable T在foreach中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆