Я обнаружил, что методам итератора в типах значений разрешено изменять this
.
Однако из-за ограничений в CLR модификации не видны вызывающим методом. (this
передается по значению)
Следовательно, идентичный код в итераторе и неитераторе дает разные результаты:
static void Main() {
Mutable m1 = new Mutable();
m1.MutateWrong().ToArray(); //Force the iterator to execute
Console.WriteLine("After MutateWrong(): " + m1.Value);
Console.WriteLine();
Mutable m2 = new Mutable();
m2.MutateRight();
Console.WriteLine("After MutateRight(): " + m2.Value);
}
struct Mutable {
public int Value;
public IEnumerable<int> MutateWrong() {
Value = 7;
Console.WriteLine("Inside MutateWrong(): " + Value);
yield break;
}
public IEnumerable<int> MutateRight() {
Value = 7;
Console.WriteLine("Inside MutateRight(): " + Value);
return new int[0];
}
}
Вывод:
Inside MutateWrong(): 7 After MutateWrong(): 0 Inside MutateRight(): 7 After MutateRight(): 7
Почему это не ошибка компилятора (или, по крайней мере, предупреждение) для мутации структуры в итераторе?
Это поведение - тонкая ловушка, которая не легко понятна.
Анонимные методы, которые имеют одинаковое ограничение, не могут использовать this
вообще.
Примечание: изменчивые структуры являются злыми; это никогда не должно возникать на практике.