2011-01-22 2 views
2
string reference; 
do { 
    reference = GenerateNewReference(); 
} while (currentItems.Exists(i=>i.Reference.Equals(reference)); 

ReSharper предупреждает меня об этом, что называется Access to Modified Closure. Я старался изо всех сил читать и понимать это, но мой код по-прежнему кажется мне хорошим.Do .. While .. with Exists предикаты. Доступ к модифицированному закрытию?

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

ответ

2

Нет, проблем нет, потому что метод 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))); 
4

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

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

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

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