c# - 这段代码真的会导致 "access to modified closure"问题吗?

标签 c# .net linq closures

采用以下代码,Resharper 告诉我 voicesSoFarvoicesNeededMaximum 导致“访问修改后的闭包”。我读到了这些,但令我困惑的是,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/

相关文章:

c# - Linq 从两个列表中返回所有元素对?

c# - Entity Framework 6 + Oracle如何查询两个结构相同的表

c# - HttpClient,一次调用产生多个异步结果

c# - 建立一个安全库,我想我过度 build 了

.net - .NET方法将一个数字四舍五入到另一个数字的最接近倍数?

linq - 在 LINQ to 实体中何时使用 JOIN 以及何时不使用

c# - 无法创建用于对LINQ查询进行排序的Func表达式

c# - 用 c# 中的 2 个换行符替换 1 个换行符

c# - ASP.NET WebAPI : No type was found that matches the controller named 'xxxx'

c# - 使用 C# 指针