Do.. While.. 使用 Exists 谓词。访问修改后的闭包?

Posted

技术标签:

【中文标题】Do.. While.. 使用 Exists 谓词。访问修改后的闭包?【英文标题】:Do.. While.. with Exists predicates. Access to modified closure? 【发布时间】:2011-06-13 16:10:32 【问题描述】:
string reference;
do 
  reference = GenerateNewReference();
 while (currentItems.Exists(i=>i.Reference.Equals(reference));

ReSharper 正在警告我这点,称为 Access to Modified Closure。我已尽力阅读并理解它,但我的代码对我来说仍然很好。

我的代码有问题吗?

【问题讨论】:

【参考方案1】:

在您的情况下这很好,因为 reference 的值在您的 lambda 的生命周期内不会改变。但resharper不知道这一点。据 resharper 所见,lambda 可能会在 reference 更改其值期间存活更长的时间。

该规则旨在在您编写如下代码时发出警告:

int myInt=1;
Func<int,bool> IsOne = i=>i==myInt;
myInt=2;
IsOne(1);//=> false
IsOne(2);//=> true

因为IsOne lambda 通过引用而不是值绑定到myInt

【讨论】:

【参考方案2】:

不,没有问题,因为List&lt;T&gt;.Exists 方法会急切地执行。因此,捕获变量值的变化会立即“响应”。你确实有一个修改过的闭包,但这并不一定是错误的(在这种情况下)。

另一方面,如果您将“lambda”(实际上是委托)添加到循环内的列表中,然后运行这些查询,您将遇到 Resharper 的实际修改闭包问题警告你。

如果想摆脱警告,你可以这样做:

string reference;
do 
  reference = GenerateNewReference();
  var refCopy = reference;
 while (currentItems.Exists(i => i.Reference.Equals(refCopy));

稍微偏离主题:如果您想要一种编写搜索的方式(没有任何修改关闭警告),您可以编写一个实用方法,例如:

public static IEnumerable<T> Generate(Func<T> func)
 
     if(func == null)
        throw new ArgumentNullException("func");

     while(true)
        yield return func();

然后将其用作:

var result = MyExtensions.Generate(GenerateNewReference)
                         .First(reference => !currentItems.Exists(i => i.Reference.Equals(reference)));

【讨论】:

以上是关于Do.. While.. 使用 Exists 谓词。访问修改后的闭包?的主要内容,如果未能解决你的问题,请参考以下文章

神奇的 SQL 之谓词 → 难理解的 EXISTS

PostgreSQL谓词之EXISTS

do…while循环

各位懂软件,的分别使用while和do…whil循环输出1—10之间的所有数字,包括1和10这题咋做

是否存在必须使用 while/do-while 而不是 for 的情况?

我不能使用 file_exists 上传脚本