Обновление : Ну, теперь я пошел и сделал это: Я отправил отчет об ошибке в Microsoft по поводу этого, так как я серьезно сомневаюсь, что это правильное поведение. Тем не менее, я все еще не уверен на 100%, чему верить в отношении этого вопроса ; так что я вижу, что то, что «правильно», открыто для некоторого уровня интерпретации.
Я считаю, что либо Microsoft согласится с тем, что это ошибка, либо ответит, что изменение переменной типа изменяемого значения в операторе using
представляет собой неопределенное поведение.
Кроме того, для чего это стоит, у меня есть хотя бы предположение о том, что здесь происходит. Я подозреваю, что компилятор создает класс для закрытия, «поднимая» локальную переменную до поля экземпляра этого класса; и поскольку он находится внутри блока с использованием
, он делает поле только для чтения
. Как указал LukeH в комментарии к другому вопросу , это помешает вызовам методов, таким как MoveNext
, изменять само поле (вместо этого они будут влиять на копию).
Примечание. : Я сократил этот вопрос для удобства чтения, хотя он все еще не совсем короткий. Полностью исходный (более длинный) вопрос см. В истории редактирования.
Я прочитал то, что, по моему мнению, является соответствующими разделами ECMA-334, и не могу найти окончательного ответа на этот вопрос. Сначала я сформулирую вопрос, а затем дам ссылку на некоторые дополнительные комментарии для тех, кому интересно.
Если у меня есть изменяемый тип значения, реализующий IDisposable
, я могу (1) вызовите метод, который изменяет состояние значения локальной переменной в , используя оператор
, и код ведет себя так, как я ожидал. Однако, как только я фиксирую рассматриваемую переменную внутри замыкания внутри , using
оператор, (2) модификации значения больше не видны в локальной области.
Такое поведение очевидно только в том случае, когда переменная фиксируется внутри замыкания и в пределах с использованием
] заявление; это не очевидно, когда присутствует только одно ( с использованием
) или другое условие (закрытие).
Почему захват переменной изменяемого типа значения внутри замыкания в с использованием
] меняет свое локальное поведение?
Ниже приведены примеры кода, иллюстрирующие пункты 1 и 2. В обоих примерах будет использоваться следующий демонстрационный Мутабельный
тип значения:
struct Mutable : IDisposable
{
int _value;
public int Increment()
{
return _value++;
}
public void Dispose() { }
}
с использованием блока
using (var x = new Mutable())
{
Console.WriteLine(x.Increment());
Console.WriteLine(x.Increment());
}
Выходной код выводит:
0 1
с использованием блока
using (var x = new Mutable())
{
// x is captured inside a closure.
Func closure = () => x.Increment();
// Now the Increment method does not appear to affect the value
// of local variable x.
Console.WriteLine(x.Increment());
Console.WriteLine(x.Increment());
}
Приведенный выше код выводит:
0 0
Было отмечено, что компилятор Mono обеспечивает поведение, которое я ожидаю (изменения в значение локальной переменной все еще отображается в с использованием
+ случай закрытия). Мне неясно, правильно ли это поведение или нет.
Еще несколько моих мыслей по этому поводу см. здесь .