做..虽然..与Exists谓词。访问修改后的闭包?

时间:2011-01-22 13:24:07

标签: c# lambda resharper predicate

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

ReSharper正在警告我这件事,称为Access to Modified Closure。我已尽力阅读并理解它,但我的代码对我来说似乎还不错。

我的代码有问题吗?

2 个答案:

答案 0 :(得分:4)

在你的情况下很好,因为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,而不是通过值绑定。

答案 1 :(得分:2)

不,没有问题,因为List<T>.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)));