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

前端之家收集整理的这篇文章主要介绍了c# – LINQ投影(选择)返回奇数结果前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
请考虑以下代码
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();
        }
    }
}

重现步骤

>在Console.Read()上放置一个断点
>运行到断点
>检查次数(应显示0)
>检查值2并填充“结果视图”
>检查数(应显示100)

问题

鉴于我仅从值1中获取了50个项目,我期望计数显示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();
        }
    }
}

检查次数

检查值2(填充结果视图)

检查次数

关于这里发生了什么的解释,以及如何解决

注意

许多给定的答案表明延期执行.我知道linq使用延期执行,所以除非我错过了一些事情,这不是问题.

我的观点是当断点被击中时,CLR已创建一个状态机为值2.然后在调试器中迭代,计数立即增加到100,看来只有1次迭代.这似乎有点奇怪!

此外,我知道随后的值2的结果视图的人口数量增加,因为这导致状态机的进一步迭代.

解决方法

每次检查值2时,表达式将再次进行评估,如果您在监视窗口中检查该表达式,则每次都会进行两次评估(不要问我为什么;询问编写监视窗口代码的人员).我得到了count == 300.每当有一些评估它,它增加50计数;这就是代码所做的,看看你自己.并且每次在观察窗口中展开它,计数增加100.所以,观察窗口评估它两次.

你只看到那些时代,但是呢?许多东西都在VS代码里面,它不麻烦给你看. GUI不是进入程序内部的窗口;屏幕上有一些像素,一些代码有意识地着色.我可以编写一个监视窗口,评估表达十九次,并显示一个口袋妖怪.什么是更合理的解释:你从未见过的一些代码是做一些不会在GUI中显示的东西,或者有时您的计算机无法添加

查看值2的运行时类型:System.Linq.Enumerable.WhereSelectEnumerableIterator< int,int&gt ;.这是没有收集,这是等待执行的. 我们将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>中.

故事的道德启示:

屏幕上的点是幻觉,结合懒惰评估与副作用就像用机枪在星巴克放松猴子.我不是说这是错的,只是不是每个人都有一个有趣的日子.

原文链接:https://www.f2er.com/csharp/92981.html

猜你在找的C#相关文章