Делай .. пока .. с предикатами Exists.Доступ к измененному закрытию? - PullRequest
2 голосов
/ 22 января 2011
string reference;
do {
  reference = GenerateNewReference();
} while (currentItems.Exists(i=>i.Reference.Equals(reference));

ReSharper предупреждает меня об этом, что называется Доступ к измененному закрытию. Я старался изо всех сил читать и понимать это, но мой код все еще кажется мне хорошим.

Есть ли проблема с моим кодом?

Ответы [ 2 ]

4 голосов
/ 22 января 2011

Это нормально в вашем случае, потому что значение reference не меняется в течение срока службы вашей лямбды.Но Решарпер не знает этого.Насколько resharper может видеть, что лямбда может выжить в течение более длительного времени, в течение которого reference меняет свое значение.

Правило предназначено для предупреждения вас, когда вы пишете такой код:

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

потому что IsOne лямбда связывается с myInt по ссылке, а не по значению.

2 голосов
/ 22 января 2011

Нет, проблем нет, потому что метод List<T>.Exists выполняется с нетерпением. Следовательно, изменения в значении захваченной переменной немедленно «реагируются». У вас do есть измененное закрытие, но это не обязательно (как в этом случае) неправильно.

С другой стороны, если бы вы добавили «лямбду» (на самом деле делегат) в список внутри цикла, а затем запустили эти запросы, вы столкнулись бы с реальными проблемами с изменением-закрытием, которыми является 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)));
...