这是否code真正引起"获得修改关闭"问题? [英] Does this code really cause an "access to modified closure" problem?

查看:115
本文介绍了这是否code真正引起"获得修改关闭"问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

采取以下code,ReSharper的告诉我, voicesSoFar voicesNeededMaximum 事业访问修改关闭。我读到这些,但在这里有什么困惑我的是ReSharper的建议通过LINQ查询之前提取的变量来正确解决这个。但是,这是他们在哪里了!

ReSharper的停止抱怨,如果我只是添加 INT voicesSoFar1 = voicesSoFar 之后 INT voicesSoFar = 0 。是否有一些奇怪的逻辑,我不明白,这使得ReSharper的的建议是否正确?或者是有办法安全地在这样的情况下,接入修改倒闭潮,而不会造成错误?

  //这需要选民,而我们只有不到300的声音
INT voicesSoFar = 0;
INT voicesNeededMaximum = 300;
VAR eligibleVoters =
    voters.TakeWhile((P =>(voicesSoFar + = p.Voices)< voicesNeededMaximum));
 

解决方案

您有一个非常棘手的问题是源于突变的外部变量在lambda EX pression。问题是这样的:如果你试图遍历 eligibleVoters 两次(的foreach(VAR在eligibleVoters选民){Console.WriteLine(voter.Name);} 和后立即(的foreach(在eligibleVoters VAR选民){Console.WriteLine(voter.Name);} )你不会看到相同的输出,这是不从功能编程的角度正确。

下面是会累积,直到蓄能某些条件扩展方法是正确的:

 公共静态的IEnumerable< T> TakeWhileAccumulator< T,TAccumulate>(
    这IEnumerable的< T>元素,
    TAccumulate种子,
    FUNC< TAccumulate,T,TAccumulate>累加器,
    FUNC< TAccumulate,布尔> predicate
){
    TAccumulate累积=种子;
    的foreach(T中的元素元素){
        如果(!predicate(累加)){
            产生中断;
        }
        累积=累加器(累积,元素);
        得到的回报元素;
    }
}
 

用法:

  VAR eligibleVoters = voters.TakeWhileAccumulator(
                         0,
                         (票,P)=>票+ p.Voices,
                         I => I< 300
                     );
 

因此​​,上面说,累积的声音,而我们具备累计不少于300票。

然后用

 的foreach(在eligibleVoters VAR项){Console.WriteLine(item.Name); }
Console.WriteLine();
的foreach(在eligibleVoters VAR项){Console.WriteLine(item.Name); }
 

输出是:

 爱丽丝
短发
凯瑟琳

爱丽丝
短发
凯瑟琳
 

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));

解决方案

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:

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;
    }
}

Usage:

var eligibleVoters = voters.TakeWhileAccumulator(
                         0,
                         (votes, p) => votes + p.Voices, 
                         i => i < 300
                     );

Thus the above says accumulate voices while we have accumulated less than 300 votes.

Then with:

foreach (var item in eligibleVoters) { Console.WriteLine(item.Name); }
Console.WriteLine();
foreach (var item in eligibleVoters) { Console.WriteLine(item.Name); }

Output is:

Alice
Bob
Catherine

Alice
Bob
Catherine

这篇关于这是否code真正引起&QUOT;获得修改关闭&QUOT;问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆