gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 17:34:50 25 4
gpt4 key购买 nike

考虑以下代码

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 并填充结果 View
  5. 检查 count++(应显示 100)

问题

鉴于我只从 values1 中取出了 50 个项目,我希望 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++

enter image description here

检查 values2(填充结果 View )

enter image description here

检查 count++

enter image description here

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

注意

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

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

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

最佳答案

每次检查values2 , 表达式被再次求值——如果你在监 window 口中检查它,它似乎每次被求值两次(不要问我为什么;问问写监 window 口代码的人).我得到了 count == 300 .每次对它进行评估时,它都会添加 50count ;这就是代码的作用,你自己看看。每次在监 window 口中展开它时,count增加 100。因此,监 window 口对其求值两次。

您只看到其中一次,那又怎样? VS 代码中有很多东西不会费心向您展示。 GUI 不是进入程序内部的窗口;它是屏幕上的一堆像素,一些代码故意在其中着色。我可以编写一个监 window 口,对表达式求值 19 次并向您显示一个 Pokemon。更合理的解释是什么:您从未见过的某些代码正在执行某些不会恰好显示在 GUI 中的操作,或者有时您的计算机无法添加?

查看values2的运行时类型: System.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> 中.

故事的寓意:

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

关于c# - LINQ 投影(选择)返回奇数结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38768937/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com