LINQ投影(选择)返回奇数结果

马修·莱顿(Matthew Layton)

考虑以下代码

namespace ConsoleApp1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public class Program
    {
        public static void Main(string[] args)
        {
            int count = default(int);

            IEnumerable<int> values1 = Enumerable.Range(1, 200)
                .OrderBy(o => Guid.NewGuid())
                .Take(100);

            IEnumerable<int> values2 = values1
                .OrderBy(o => Guid.NewGuid())
                .Take(50)
                .Select(o => { count++; return o; });

            Console.Read();
        }
    }
}

重现步骤

  1. 设置一个断点 Console.Read();
  2. 跑到断点
  3. 检查count++(应显示0)
  4. 检查values2并填充结果视图
  5. 检查count++(应显示100)

问题

鉴于我只从中取出了50个项目values1,因此我希望count++显示50。为什么显示100?

请注意,如果这令人困惑,请尝试运行此代码,它会产生相同的结果...

namespace ConsoleApp1
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public class Program
    {
        public static void Main(string[] args)
        {
            int count = default(int);

            IEnumerable<int> values1 = Enumerable.Range(1, 100)
                .OrderBy(o => Guid.NewGuid())
                .Take(50);

            IEnumerable<int> values2 = values1
                .OrderBy(o => Guid.NewGuid())
                .Take(50)
                .Select(o => { count++; return o; });

            Console.Read();
        }
    }
}

例子

检查 count++

在此处输入图片说明

检查values2(填充结果视图)

在此处输入图片说明

检查 count++

在此处输入图片说明

关于这里发生的事情以及如何解决的任何解释?

笔记

许多给出的答案都建议推迟执行。我知道linq使用延迟执行,所以除非我缺少什么,否则这不是问题。

我的观点是,当遇到断点时,CLR为values2创建了一个状态机。然后在调试器中对其进行迭代,对于似乎只有1次迭代的计数立即增加到100。这似乎有点奇怪!

另外,我知道value2的结果视图的后续填充会导致计数增加,因为这会导致状态机的进一步迭代。

15ee8f99-57ff-4f92-890c-b56153

每次检查时values2,都会重新评估该表达式-如果您在监视窗口中对其进行检查,它似乎每次都会被评估两次(不要问我为什么;请问编写监视窗口代码的人)。我知道了count == 300每当某计算它,把它添加50count; 这就是代码的作用,请自己看看。并且,每次在监视窗口中将其扩展时,它都会count增加100。因此,监视窗口对其进行两次评估。

您只看到其中一次,那又如何呢?VS代码中包含许多内容,因此不会显示给您。GUI不是进入程序内部的窗口;它不是程序内部的窗口。它是屏幕上的一堆像素,有些代码是故意着色的。我可以编写一个观察窗口,对表达式进行19次评估,并向您显示Pokemon。更合理的解释是:您从未见过的某些代码正在执行某种可能不会在GUI中显示的操作,或者有时您的计算机无法添加?

看看运行时类型values2System.Linq.Enumerable.WhereSelectEnumerableIterator<int, int>那不是集合,那是等待执行的东西。

让我们添加ToList()到该表达式的末尾。它将对其进行一次评估并存储结果。然后,您可以整天检查结果,而无需再次执行任何LINQ表达式。

int count = default(int);

IEnumerable<int> values1 = Enumerable.Range(1, 200)
    .OrderBy(o => Guid.NewGuid())
    .Take(100);

IEnumerable<int> values2 = values1
    .OrderBy(o => Guid.NewGuid())
    .Take(50)
    .Select(o => { count++; return o; })
    .ToList();

现在count == 50,由于该表达式只计算一次,结果存储在中List<T>

这个故事所讲的道德:

屏幕上的点是一种错觉,将懒惰的评估与副作用结合起来,就像用机枪将猴子放到星巴克中一样。我并不是说这是错误的,并不是所有人都认为有一个有趣的约会。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

实物投影仪返回奇怪的结果

来自分类Dev

感知器收敛但返回奇数结果

来自分类Dev

返回奇数结果的日期之间的比较

来自分类Dev

MySQL LIKE 语句返回奇数结果

来自分类Dev

返回LINQ查询结果

来自分类Dev

LINQ返回空结果

来自分类Dev

Linq 返回分组结果

来自分类Dev

选择返回无结果

来自分类Dev

无法从查询返回linq结果

来自分类Dev

Linq使用选择选择子结果

来自分类Dev

Linq使用选择选择子结果

来自分类Dev

美丽的汤find_all()返回奇数标签而不是结果

来自分类Dev

需要帮助以了解为什么COUNT DISTINCT返回奇数结果

来自分类Dev

动态Linq选择-如何提取结果

来自分类Dev

带连接的SQL选择返回双倍结果

来自分类Dev

MySQL选择查询不必返回结果集

来自分类Dev

带连接的SQL选择返回双倍结果

来自分类Dev

dql 选择返回空结果 symfony 3

来自分类Dev

Linq Join选择以返回拼合列表

来自分类Dev

X ++奇数计数结果

来自分类Dev

Linq to SQL从查询返回多个计数而不返回正确的结果

来自分类Dev

Linq实体。嵌套投影

来自分类Dev

使用LINQ动态投影

来自分类Dev

使用LINQ动态投影

来自分类Dev

LINQ包含和投影

来自分类Dev

从linq投影到键值对

来自分类Dev

弹簧投影选择集合

来自分类Dev

如何在C#中使用Linq从泛型创建动态选择投影?

来自分类Dev

LINQ to SQL通过投影上的字符串选择属性名称