Делать .. Пока .. с предикатами Exists. Доступ к измененному закрытию?

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

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

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


person Jak S    schedule 22.01.2011    source источник


Ответы (2)


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

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

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

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

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

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

person CodesInChaos    schedule 22.01.2011