Почему переменная класса связанного списка С# не сохраняет свое значение после ее назначения?

Я создаю генератор кроссвордов и, похоже, у меня проблема с простым переменным назначением координат в системе сетки. У меня очень простая структура для хранения дискретных значений координат, как показано ниже. Я убрал инкапсуляцию, чтобы было легче читать.

    public struct vec2
    {
        public int x, y;
        public vec2(int x, int y)
        {
            this.x = x;
            this.y = y;
        }
    }

Эта структура Vec2 поддерживается внутри класса для хранения значений слов.

public struct WordClass
{
    string svalue;
    bool flag;
    public vec2 position;

    public WordClass(string sarg, bool barg)
    {
        this.svalue = sarg;
        this.flag = barg;
        position = new vec2(0,0);
    }
    public string StringVal
    {
        get { return svalue; }
    }
    public bool FlagVal
    {
        get { return flag; }
    }
    public void DisableWord()
    {
        if (this.flipflop == false)
        {
            this.flipflop = true;
        }
    }
    public void SetPos(int xa, int ya)
    {
        this.position.x = xa;
        this.position.y = ya;
    }
}

В основном это должно поддерживать список постоянных слов с флагом для использования и переменной позицией, поскольку система вычисляет оптимальные местоположения для слова.

У меня есть динамически связанный список слов

    List<WordClass> WordList = new List<WordClass>();

и изменить координаты слова в списке слов

    //Arbitrary values
    WordList[0].SetPos(Position_X, Position_Y);

Теперь моя проблема заключается в том, что когда я пытаюсь использовать позицию слова, независимо от того, что я установил слишком рано, она сохраняет значение по умолчанию 0, 0. Я почесал голову, выполняя другие функции, и это оставило меня интересно, если я пропускаю что-то важное.


person Byren Higgin    schedule 27.09.2015    source источник
comment
Ознакомьтесь с разделом Когда использовать структуру?. Ваши структуры являются изменяемыми, что может вызвать подобные проблемы, когда вы пытаетесь установить значение, но оно не сохраняется, потому что вы фактически меняете значение в копии структуры. Я не думаю, что вы должны использовать структуры здесь.   -  person 31eee384    schedule 27.09.2015
comment
Спасибо за ссылку, я все еще программист-любитель, и я думал, что классы и структуры полностью взаимозаменяемы в С#. Кажется, это в основном решило мою проблему.   -  person Byren Higgin    schedule 27.09.2015


Ответы (1)


Похоже, проблема связана с тем, что vec2 является ValueObject, и вы пытаетесь его изменить. Проблемные строки - это конкретно эти две:

this.position.x = xa;
this.position.y = ya;

Почему? Поскольку vec2 является struct, каждый раз, когда вы читаете его, вы получаете временную копию, затем изменяете эту копию, затем копия выбрасывается, пока вы все еще читаете исходную, неизмененную. Это одна из причин, по которой объекты-значения должны быть неизменяемыми настолько, насколько это возможно, если только у вас нет веской причины.

Первым шагом должно быть создание правильной неизменяемой структуры vec2:

public struct vec2
{
    public int x { get; private set; }
    public int y { get; private set; }

    public vec2(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

Как только вы это сделаете, вам нужно позаботиться об модификации метода SetPos. Поскольку структура неизменяема, вы больше не можете ее читать, но вместо этого каждый раз, когда вам нужно ее изменить, вы отбрасываете текущий экземпляр и создаете новый:

public void SetPos(int xa, int ya)
{
    this.position = new vec2(xa, ya);
}

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

person Alejandro    schedule 27.09.2015
comment
vec2 — это структура, и каждый раз, когда вы ее читаете, вы получаете временную копию. Вы уверены, что это происходит в этом конкретном случае? Обратите внимание, что у нас есть List<WordClass>, а WordClass это тоже struct. - person AlexD; 27.09.2015
comment
Спасибо за это. В сочетании с комментарием, сделанным на мой вопрос @ 31eee384, он полностью решил мою проблему. Это было связано с временными копиями и структурами. - person Byren Higgin; 27.09.2015
comment
@AlexD Это только усугубит проблему, поэтому проблема с временным копированием может возникнуть дважды. Я не проверял так тщательно, как следовало бы, но проблема с изменяемыми структурами все же есть. Тем не менее, когда у меня будет под рукой компилятор, я проверю: D - person Alejandro; 27.09.2015
comment
@Alejandro Если мы получим доступ к полю position, как в данном коде, копия структуры не должна создаваться. - person AlexD; 27.09.2015