Почему resharper предлагает «переменную обертки в массиве» для доступа к измененным предупреждениям о закрытии? - PullRequest
21 голосов
/ 24 июня 2011

Учитывая следующий (сильно отредактированный, псевдо-) код:

int count = 0;
thing.Stub(m => m.AddBlah()).WhenCalled(o => count++);
thing.Stub(m => m.RemoveBlah()).WhenCalled(o => count--);

DoStuff(thing);

Assert.AreEqual(1, count);

ReSharper выдает предупреждение на счет - «Доступ к измененному закрытию». Я понимаю, почему я получаю это предупреждение (переменная count изменяется в двух разных лямбдах и, вероятно, имеет нежелательную семантику), но я не понимаю рекомендации ReSharper: «Обернуть локальную переменную в массив». Если я позволю ReSharper сделать это, я получу:

int count[] = { 0 };
thing.Stub(m => m.AddBlah()).WhenCalled(o => count[0]++);
thing.Stub(m => m.RemoveBlah()).WhenCalled(o => count[0]--);

DoStuff(thing);

Assert.AreEqual(1, count[0]);

И без предупреждения.

Почему использование массива безопасно?

Ответы [ 2 ]

13 голосов
/ 27 ноября 2012

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

Как вы уже видели, результат одинаков, независимо от того, обернут ли он в массив или нет, поэтому рефакторинг на самом деле ничего не "исправляет" и возникают те же проблемы, с которыми можно столкнуться при обращении к обычному измененному замыканию после применения менять. Однако после изменения, поскольку сам массив count не изменяется (только его содержимое), предупреждение «Доступ к измененному закрытию» больше не актуально.

Изменение на самом деле не делает проблему более очевидной (по крайней мере, на мой взгляд), поэтому может показаться, что это предложение по сути говорит ReSharper игнорировать проблему, не прибегая к довольно грязной // ReSharper disable AccessToModifiedClosure механизм подавления ошибки.

1 голос
/ 25 июня 2011

Это потому, что 2 типа разные. Int является типом Value, а массив является ссылочным типом. Это означает, что int находится в стеке, а указатель массива - в стеке.

Когда вы обновляете тип значения, он обновляет этот фрагмент стековой памяти. Тип Reference, с другой стороны, оставляет этот фрагмент стековой памяти в одиночестве и изменяет то, на что он указывает.

Resharper не жалуется на массив, потому что 2 различных метода Lambda создают замыкание вокруг памяти, которое указывает, где обновить значение. Обе лямбды получают один и тот же адрес и не меняют оригинал.

...