- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
请引用下面的 LinqPad 脚本。
在实现工作流时,我从集合 (IEnumerable) 中获取下一组 HasRun
任务。在迭代 Linq 查询的结果集时,我将任务更改为 HasRun = true
。调试显示我最初得到了四个对象的预期子集,但是,在所有子集都被标记之后,可枚举突然解析到下一个子集并且 foreach 循环也在该集合上继续,然后是下一个,等等。
因此,当我希望迭代四次时,它会一直进行,直到迭代完所有三个子集(9 个项目)。这很容易通过 .ToList()
枚举来解决,但我想知道这是否是故意的行为。
在谷歌搜索中,我发现了对迭代变量“不可预测的行为”的引用,this old post being one example, on which @jon skeet commented on ,但是最新的 c# 规范(第 8.8.4 节)没有提到不可预测的行为,它只是提到了赋值、递增和递减的问题:
A compile-time error occurs if the embedded statement attempts to modify the iteration variable (via assignment or the ++ and operators) or pass the iteration variable as a ref or out parameter.
这是设计使然的行为吗?
void Main()
{
List<Foo> foos = new List<UserQuery.Foo>
{
new Foo{ SetNbr = 1, HasRun = false },
new Foo{ SetNbr = 1, HasRun = false },
new Foo{ SetNbr = 1, HasRun = false },
new Foo{ SetNbr = 1, HasRun = false },
new Foo{ SetNbr = 2, HasRun = false },
new Foo{ SetNbr = 2, HasRun = false },
new Foo{ SetNbr = 3, HasRun = false },
new Foo{ SetNbr = 3, HasRun = false },
new Foo{ SetNbr = 3, HasRun = false }
};
//Grab the first subset of Foos where HasRun is false, in order of SetNbr
var firstNotRunGroup = foos.Where(a => a.SetNbr == (foos.Where(f => f.HasRun == false).Min(f => f.SetNbr)));
foreach (Foo foo in firstNotRunGroup)
{
//foo = new Foo(); < Fails, as expected
foo.HasRun = true;
Console.WriteLine(foo.SetNbr);
}
}
class Foo
{
public int SetNbr { get; set; }
public bool HasRun { get; set; }
}
输出:
11个1个1个2个2个3个3个3
最佳答案
您必须记住,LINQ 操作返回查询,而不是执行查询的结果。每次迭代 LINQ 序列时,它都会重新计算当时该查询的结果。这意味着如果您的查询基于某些底层集合或数据存储(在本例中,您使用的是列表)并且数据发生变化,则查询的后续迭代将反射(reflect)这些变化。
除此之外,LINQ 查询会尽其所能在迭代期间尽可能多地推迟计算;他们只计算提供下一个值所需的数量。这意味着在枚举期间对基础数据存储的更改可能会影响涉及查询其余部分的计算方式的计算。
那么,你的代码做了什么。首先声明一个查询 firstNotRunGroup
,它实际上不执行任何操作。
然后我们开始在 foreach
中迭代 firstNotRunGroup
。它执行谓词,a
是列表中的第一项。 a.SetNbr
为 1
。然后我们查询 foos
寻找未运行项目的最低集合数。那将是 1
,它是一个匹配项,因此返回第一个项目。然后,我们将该项目的 HasRun
设置为 true 并将其打印出来。
现在 foreach
去检查第二项是否匹配。再次查询 foos
并且未运行项目的最低集合编号是 1
,这是第二个项目的匹配项,因此它运行它。这种情况又发生了两次。
现在列表中的前四项都已运行,foreach
现在将检查是否应返回列表中的第五项。 SetNbr
是 2
,当它遍历 foo
以查看未运行项的最小集合号是多少时,它会看到所有第一组中的项目已经运行,因此 2
是尚未运行的项目的最小组数。 2
匹配我们正在查询的项目的设置编号,因此应该运行它。
从这两个模式可以看出,集合中的每个项目最终都会运行。有很多事情可以改变这一点;如果列表中没有按集合编号升序排列的项目,则整个事情都会中断(以不同的方式,具体取决于列表的排序方式),如果您使用尚未运行的项目计算最小集合一次,而不是为集合中的每个项目重新计算该值,这不会发生(并且您的代码也不会如此可怕地扩展),或者,如您所说,如果您计算了整个项目集第一组在您开始运行这些项目之前 未运行,那么您将不会得到此结果。
关于c# - 说明在 foreach 期间更改属性时可枚举的 "unpredictable behavior",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40611850/
是否有办法获得一个 Behavior t [a],其中时间 t 时 [a] 的值是 Behavior t [Behavior t a] 中包含的值> 在时间 t?即,具有以下类型的函数: Behavi
(问题最初是由对 Are there race conditions in this producer-consumer implementation? 的回答下的评论提示的,但这里严格从 C 语言的
摘自本文:http://www-public.int-evry.fr/~gibson/Teaching/CSC7322/ReadingMaterial/Wegner87.pdf 它定义类型: type
阅读Akka 2.6.10 API Docs ,akka.actor.typed.scaladsl.Behaviors.setup 和 akka.actor.typed.scaladsl.Behavi
我从 easymock 和 JUnit 测试用例中得到了一些无法解释的行为。我收到 IllegalStateException:缺少前面方法调用的行为定义:myCollaborator.getCurr
在 akka typed 中,我们有行为的概念。 如果我们想保留 Actor 的相同行为,我们会在处理完一条消息后返回 Behaviors.same。但是我们也可以返回这个。两者有何不同? 最佳答案
我正在 Kubernetes 中创建一个 HorizontalPodAutoscaler,我需要将缩减稳定窗口配置为小于默认值。使用的代码和错误如下: apiVersion: autoscalin
在 Python 中,为什么 [:] 切片操作的行为不一致? 它对于列表和字符串的行为有所不同。 对于列表,它给出一个副本列表对象,对于字符串,它给出相同的字符串对象。 我觉得这令人困惑,违反直觉。有
我需要将一些对象存储到数据库中。 首先 我将它们存储在内存中(存储在集合中) 当其中一个正确存储在数据库中时,我会将其删除 所以, public class AuditService { pr
下面的程序 (prog1) 抛出 OutOfMemoryError 错误。确实如此。但如果我在第 5 行(prog2)下方添加 sysout,它不会抛出错误。这种奇怪的行为有什么原因吗? 程序1: p
我有以下二叉搜索树(在 C++ 中),我对特定代码行有疑问: delete k; 如果我删除该行,我的代码可以正常工作,但我不明白为什么。据我了解:来自 k 的数据被插入到树中,然后变量 k 被删除。
我想知道如果我尝试对已删除或可能尚未分配的指针执行 delete 会发生什么?我读过两件事:第一,delete 运算符会做一些检查,我们不需要检查指针是否为空;然后,我读到它会导致未知的行为.. 我在
我无法解释 Scala 集合的这种行为。 让我们从一些定义开始。 import scala.collection.mutable.Set case class Item(name: String, c
我一直在尝试在 wpf 窗口上实现一种行为,因此我在当前的解决方案中添加了对 System.Winodws.Interactivity 的引用,然后编写了所需的行为。但为了应用这种行为,我必须在 Wi
我试图理解 rdpmc 指令。因此,我有以下 asm 代码: segment .text global _start _start: xor eax, eax mov ebx, 10
我正在关注这里的测试:https://github.com/plone/plone.app.referenceablebehavior/blob/master/plone/app/referencea
行为(方法体)可以是状态机或事件 - 事件很容易理解,因为它们等同于过程代码。 我不明白状态机如何用作操作的行为? 您能为此提供一个简单的示例吗? ---注意--- Operation 是一个仅规范元
我正在尝试在 Cocoa 应用程序中实现自定义终止行为。通常,当我的应用程序正常退出时,它会执行最终运行时数据库清理,然后退出。每当调用 [NSApp Terminate:aSender] 时,都会在
这里没什么太严肃的,只是好奇。 我想举个例子,想出了这段代码: const { Observable, Subject } = Rx const timeout$ = new Subject() co
我希望类中的方法在 IO 线程上运行一些代码,但只有当它们订阅的主题具有特定值时。然后调用者应该在 Android UI 线程上收到响应。 类似这样的事情: public class MyClass
我是一名优秀的程序员,十分优秀!