这段代码真的会导致“访问修改后的闭包”吗?问题?
使用以下代码,Resharper 告诉我 voicesSoFar
和 voicesNeededMaximum
导致“访问修改后的闭包”。我读到了这些内容,但令我困惑的是,Resharper 建议通过将变量提取到 LINQ 查询之前来解决此问题。但这就是他们已经在的地方了!
如果我只是在 int voicesSoFar = 0
之后添加 int voicesSoFar1 = voicesSoFar
,Resharper 就会停止抱怨。是否有一些我不明白的奇怪逻辑使 Resharper 的建议正确?或者有没有一种方法可以在此类情况下安全地“访问修改后的闭包”而不会导致错误?
// this takes voters while we have less than 300 voices
int voicesSoFar = 0;
int voicesNeededMaximum = 300;
var eligibleVoters =
voters.TakeWhile((p => (voicesSoFar += p.Voices) < voicesNeededMaximum));
Taking the following code, Resharper tells me that voicesSoFar
and voicesNeededMaximum
cause "access to a modified closure". I read about these but what puzzles me here is that Resharper suggests fixing this by extracting the variables to right before the LINQ query. But that is where they are already!
Resharper stops complaining if I merely add int voicesSoFar1 = voicesSoFar
right after int voicesSoFar = 0
. Is there some weird logic I do not understand that makes Resharper's suggestion correct? Or is there a way to safely "access modified closures" in cases like these without causing bugs?
// this takes voters while we have less than 300 voices
int voicesSoFar = 0;
int voicesNeededMaximum = 300;
var eligibleVoters =
voters.TakeWhile((p => (voicesSoFar += p.Voices) < voicesNeededMaximum));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
将外部变量转变为 lambda 表达式会产生一个非常棘手的问题。问题是这样的:如果您尝试迭代
eligibleVoters
两次 (foreach(var voter in EligibleVoters) { Console.WriteLine(voter.Name); }
并在 (< 这是不正确的。code>foreach(var voter in EligibleVoters) { Console.WriteLine(voter.Name); }) 从函数式编程的角度来看, 将累积直到累加器上的某些条件为真:
用法:
因此,上面说的是当我们累积的票数少于 300 时累积声音
然后:
输出为:
You have a very nasty problem that arises from mutating an outer variable to the lambda expression. The problem is this: if you try to iterate
eligibleVoters
twice (foreach(var voter in eligibleVoters) { Console.WriteLine(voter.Name); }
and immediately after (foreach(var voter in eligibleVoters) { Console.WriteLine(voter.Name); }
) you will not see the same output. That is just not right from a functional programming perspective.Here is an extension method that will accumulate until some condition on the accumulator is true:
Usage:
Thus the above says accumulate voices while we have accumulated less than 300 votes.
Then with:
Output is:
好吧,错误消息是正确的,因为在操作过程中未保留
voicesSoFar
的值。在纯粹的“函数式”术语中(并且 lambda 确实被设计为函数式操作),这会令人困惑。例如,一个有趣的测试是:
例如:
我相信您可以看到...
10
,null
- 令人困惑。以下内容是可重复的:如果您需要,您当然可以编写一个采用 lambda 的可重用扩展方法。
Well, the error message is correct in as much that the value of
voicesSoFar
is not preserved during the operation. In pure "functional" terms (and lambdas are really designed to act functionally) it will be confusing.For example, an interesting test would be:
For example:
I believe you can see...
10
,null
- confusing. The following would be repeatable:If you needed you could of course write a reusable extension method that took a lambda.
我怀疑修改 TakeWhile 中的“voicesSoFar”值导致了该问题。
I suspect that modifying the 'voicesSoFar' value in TakeWhile is causing the problem.