Странная ошибка компиляции структуры Foreach в С#

namespace MyNamespace
{
    public struct MyStruct
    {
        public string MyString;
        public int MyInt;
        public bool MyBool;
    }

    public class MyClass
    {
        private List<MyStruct> MyPrivateVariable;

        public List<MyStruct> MyVariable
        {
            get
            {
                if (MyPrivateVariable == null)
                {
                    MyPrivateVariable = new List<MyStruct>();

                    MyPrivateVariable.Add(new MyStruct());
                    MyPrivateVariable.Add(new MyStruct());
                }

                return MyPrivateVariable;
            }
        }

        public void MyLoop()
        {
            foreach (MyStruct ms in MyVariable)
            {
                // Doesn't compile, but it works if you execute it through the Immediate window, or in Quickwatch
                ms.MyBool = false;

                // Compiles, works
                MyFunction(ms);
            }
        }

        public void MyFunction(MyStruct ms)
        {
            ms.MyBool = false;
        }
    }
}

Есть разумные объяснения этому?

Компилятор возвращает:

Ошибка: невозможно изменить элементы «ms», поскольку это «переменная итерации foreach».

ИЗМЕНИТЬ:

Дополнительный вопрос:

Я только что попытался изменить строку с MyFunction, и на самом деле она не обновляет ms. НО: если я зайду в quickwatch и назначу там то же значение, оно обновит ms. Почему это происходит, если он вообще не должен компилироваться, не должен ли quickwatch выдавать исключение?

EDIT2:

Хорошо, быстрый просмотр также работает с копией ms, поэтому я могу редактировать его значение, на самом деле это не меняет содержимое MyPrivateVariable.


person bevacqua    schedule 24.09.2010    source источник
comment
Что говорит сообщение компилятора?   -  person CodingGorilla    schedule 24.09.2010
comment
какое сообщение об ошибке компилятора?   -  person EJC    schedule 24.09.2010
comment
Что вы подразумеваете под этим работает в Immediate? Он выполнится, но если ваша цель — обновить элементы в MyVariable, то он не сработает.   -  person recursive    schedule 24.09.2010


Ответы (5)


Вы используете их как изменяемые структуры. Избегайте этого:

Почему изменяемые структуры "злые"?

person Joel Etherton    schedule 24.09.2010

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

person Rohith    schedule 24.09.2010

C# не повторяет структуры по ссылке в «foreach (MyStruct ms...)», поэтому ms в этом контексте неизменяем.

Вместо этого замените MyStruct классом.

QuickWatch может манипулировать типами значений в стеке.

person burkestar    schedule 24.09.2010
comment
Иногда бывает полезно обернуть изменяемую структуру в простой класс Holder<T> с открытым полем для использования в определенных ситуациях, но простая замена изменяемой структуры изменяемым классом для облегчения изменения элементов в коллекциях — плохая идея. В общем, каждый изменяемый объект должен иметь ровно один другой объект, который инкапсулирует его изменяемое состояние. Если кто-то хочет скопировать что-то из одного List<Holder<MyStruct>> в существующее место в другом, List2[1].Value = List1[3].Value;. Чтобы добавить один элемент списка к другому списку, произнесите List2.Add(new Holder<MyStruct>(List1[3])). - person supercat; 18.09.2012

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

person Vinay B R    schedule 24.09.2010

Вы не можете изменить то, на что ссылается переменная итерации: то есть вы не можете указать переменную на другой экземпляр (чтобы узнать, почему это так, см. Почему переменная итерации в инструкции C# foreach доступна только для чтения?).

«Изменение» структуры (типа значения) создает новый экземпляр типа, поэтому оператор ms.MyBool = false не имеет смысла.

Вызов MyFunction(ms) компилируется, потому что он работает с копией ms (хотя он по-прежнему не делает того, что можно было бы ожидать).

person Jeff Sternal    schedule 24.09.2010
comment
тогда почему я могу изменить их в Quick Watch? Неважно, это также работает с копией структуры, почему вообще существуют структуры? - person bevacqua; 24.09.2010
comment
@Nico: У структур есть цель, но у изменяемых структур ее почти никогда не бывает. - person Adam Robinson; 24.09.2010
comment
@Nico: Все, что вы делаете, это модифицируете копию, которая затем выбрасывается. Это по сути не-операция. - person Steven Sudit; 25.09.2010