【问题标题】:For Each in LINQ Select对于 LINQ 选择中的每个
【发布时间】:2011-07-04 13:32:58
【问题描述】:

对于比我更了解 .Net 内部运作的人来说,这是一个简单的问题::-)。我只是确保我理解了一些东西。

在我看来,当您在 foreach 中运行 LINQ 时,会评估(运行)LINQ 枚举器,它返回一个集合,然后 foreach 在该集合上继续进行。但是......仍然,我不确定:

foreach (VCCTreeItem ti in (from treeItems in TreeItems select treeItems))

是否在每个循环中重新评估(执行)LINQ 语句?我会认为(并希望)不。但是,当对 foreach 中的集合进行操作时,如果集合被修改,您会在运行时收到错误消息。这让我相信幕后可能正在发生一些可疑的事情。我从来没有时间详细拆解/检查这个,所以这就是我问你这个的原因。我相信你们中的一些人从头顶上知道答案::- D.

哦,我想我可以问同样的问题:

foreach (VCCTreeItem ti in TreeItems)

如果 TreeItems 是一个属性,我在其 get 中执行了一些操作,则该属性将被评估,作为一个值返回,并且 foreach 将对该值进行操作。

【问题讨论】:

    标签: c# linq


    【解决方案1】:

    IEnumerable 未重新评估。像这样的foreach 声明:

    IEnumerable<Foo> enumerable = ...;
    foreach (Foo f in enumerable) {
        ...
    }
    

    与此相对应(编辑:enumerator 也放入 using 块中,如 @Double Down 所示):

    IEnumerable<Foo> enumerable = ...;
    IEnumerator<Foo> enumerator = enumerable.GetEnumerator();
    while (enumerator.MoveNext()) {
        Foo f = enumerator.Current;
        ...
    }
    

    因此,如果您有一些昂贵的操作会产生您正在循环的集合,那不是问题;它只会生产一次。然而,在 LINQ 中,正如@Double Down 所说,大多数结果都是延迟生成的——所以对GetEnumerator() 的调用几乎什么都不做,而每次调用MoveNext() 时都会逐渐生成结果。总的来说,这与在一次操作中生成整个列表一样耗时,但它节省了内存(包含所有元素的实际 List 永远不会生成;您一次获取一个元素,然后将其丢弃)。

    【讨论】:

    • 没问题。顺便说一句,一个有趣的学习练习是自己实现一对IEnumerableIEnumerator 类。例如,您可以创建一个类,其构造函数采用两个整数ab,当它被枚举时,它会生成ab 之间的所有整数。除了了解有关如何使用这些接口的更多信息之外,您还可以在类的实例上使用foreach,并亲自查看GetEnumerator() 只被调用一次。 :-)
    • 这是个好主意 ::- D. 但是当你站在我的立场上,尝试建立一个巨大的项目并实现你的梦想,同时靠独立预算生活,你所做的大部分事情都是免费开源,生活往往会提醒你时间是宝贵的。所以我会在没有进一步验证的情况下接受你的回答::-)。我不是懒惰,我只是时间紧迫。我知道,每个人都是。但是我也做一些开源的东西sourceforge.net/projects/mousenitor ...除了我的其他项目,现在也没有赚很多钱(读 0)。 sigh,我不知道为什么我刚刚有这个理由之旅,哈哈
    • 我明白了 - 祝你的项目好运,然后睁大眼睛寻找在生产代码中实现 IEnumerable 的机会 ;-)
    【解决方案2】:

    Linq 正在执行后期绑定评估(使用 yield 关键字)。当您在 IEnumerator 中调用 MoveNext() 时,它仅针对下一项进行评估,不会在每次移动下一个调用中从头开始重新计算。

    如您所知,您的 foreach 循环计算结果为

    using (var enumerator = enumerable.GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            // Loop body.
        }
    }
    

    【讨论】:

    • 感谢您帮助我睡得更好::- D.
    猜你喜欢
    • 2021-11-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-19
    • 1970-01-01
    • 2018-02-11
    • 2020-06-19
    相关资源
    最近更新 更多