采用以下代码,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));
最佳答案
您遇到了一个非常棘手的问题,该问题是由将外部变量变异为 lambda 表达式引起的。问题是这样的:如果您尝试迭代 eligibleVoters
两次 (foreach(var voter in eligibleVoters) { Console.WriteLine(voter.Name); }
并在 (foreach(var voter in eligibleVoters) { Console.WriteLine(voter.Name); }
) 你不会看到相同的输出。从函数式编程的角度来看,这是不对的。
这是一个扩展方法,它会累加直到累加器上的某些条件为真:
public static IEnumerable<T> TakeWhileAccumulator<T, TAccumulate>(
this IEnumerable<T> elements,
TAccumulate seed,
Func<TAccumulate, T, TAccumulate> accumulator,
Func<TAccumulate, bool> predicate
) {
TAccumulate accumulate = seed;
foreach(T element in elements) {
if(!predicate(accumulate)) {
yield break;
}
accumulate = accumulator(accumulate, element);
yield return element;
}
}
用法:
var eligibleVoters = voters.TakeWhileAccumulator(
0,
(votes, p) => votes + p.Voices,
i => i < 300
);
所以上面说的是累积投票数不到300票。
然后:
foreach (var item in eligibleVoters) { Console.WriteLine(item.Name); }
Console.WriteLine();
foreach (var item in eligibleVoters) { Console.WriteLine(item.Name); }
输出是:
Alice
Bob
Catherine
Alice
Bob
Catherine
关于c# - 这段代码真的会导致 "access to modified closure"问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2242371/