Почему захват изменяемой структурной переменной внутри замыкания внутри оператора using изменяет ее локальное поведение?

Обновление : Ну, теперь я пошел и сделал это: Я отправил отчет об ошибке в 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() { }
}

1. Преобразование переменной типа значения в с использованием блока

using (var x = new Mutable())
{
    Console.WriteLine(x.Increment());
    Console.WriteLine(x.Increment());
}

Выходной код выводит:

0
1

2. Захват переменной типа значения внутри замыкания в с использованием блока

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 обеспечивает поведение, которое я ожидаю (изменения в значение локальной переменной все еще отображается в с использованием + случай закрытия). Мне неясно, правильно ли это поведение или нет.

Еще несколько моих мыслей по этому поводу см. здесь .

20
задан Community 23 May 2017 в 12:24
поделиться