Структура foreach странная ошибка компиляции в C # - PullRequest
3 голосов
/ 24 сентября 2010
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 итерация переменная '

EDIT:

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

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

EDIT2:

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

Ответы [ 5 ]

14 голосов
/ 24 сентября 2010

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

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

6 голосов
/ 24 сентября 2010

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

5 голосов
/ 24 сентября 2010

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

Вместо этого вместо MyStruct следует использовать класс.

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

1 голос
/ 24 сентября 2010

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

0 голосов
/ 24 сентября 2010

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...