Подтвердить что ты не робот

Почему resharper предлагает "wrap variable in array" для доступа к модифицированным предупреждениям о закрытии?

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

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 изменяется в двух разных lambdas и, вероятно, имеет нежелательную семантику), но я не понимаю совета ReSharper: "Wrap local variable in array". Если я разрешу 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]);

И никаких предупреждений.

Почему безопасный массив?

4b9b3361

Ответ 1

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

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

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

Ответ 2

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

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

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