Изменить переменную Struct в словаре - PullRequest
32 голосов
/ 06 июня 2011

У меня есть такая структура:

public struct MapTile
{
    public int bgAnimation;
    public int bgFrame;
}

Но когда я зацикливаюсь на нем с помощью foreach, чтобы изменить кадр анимации, я не могу этого сделать ...

Вот код:

foreach (KeyValuePair<string, MapTile> tile in tilesData)
{
        if (tilesData[tile.Key].bgFrame >= tilesData[tile.Key].bgAnimation)
        {
            tilesData[tile.Key].bgFrame = 0;
        }
        else
        {
            tilesData[tile.Key].bgFrame++;
        }
}

Это дает мне ошибку компиляции:

* * 1010

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

Ответы [ 4 ]

42 голосов
/ 06 июня 2011

Индексатор вернет копию значения. Внесение изменений в эту копию не повлияет на значение в словаре ... компилятор не дает вам писать ошибочный код. Если вы хотите изменить значение в словаре, вам нужно использовать что-то вроде:

// Note: copying the contents to start with as you can't modify a collection
// while iterating over it
foreach (KeyValuePair<string, MapTile> pair in tilesData.ToList())
{
    MapTile tile = pair.Value;
    tile.bgFrame = tile.bgFrame >= tile.bgAnimation ? 0 : tile.bgFrame + 1;
    tilesData[pair.Key] = tile;
}

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

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

Конечно, другая альтернатива - сделать ее ссылочным типом, и в этот момент вы можете использовать:

// If MapTile is a reference type...
// No need to copy anything this time; we're not changing the value in the
// dictionary, which is just a reference. Also, we don't care about the
// key this time.
foreach (MapTile tile in tilesData.Values)
{
    tile.bgFrame = tile.bgFrame >= tile.bgAnimation ? 0 : tile.bgFrame + 1;
}
7 голосов
/ 06 июня 2011

tilesData[tile.Key] не является местом хранения (т.е. это не переменная). Это копия экземпляра MapTile, связанного с ключом tile.Key в словаре tilesData. Это то, что происходит с struct. Копии их экземпляров передаются и возвращаются везде (и это большая часть того, почему изменяемая структура считается злой).

Что вам нужно сделать, это:

    MapTile tile = tilesData[tile.Key];
    if (tile.bgFrame >= tile.bgAnimation)
    {
        tile.bgFrame = 0;
    }
    else
    {
        tile.bgFrame++;
    }
    tilesData[tile.Key] = tile;
1 голос
/ 28 августа 2012

Я бы предложил создать служебный класс:

public class MutableHolder<T>
{
    public T Value;
    public MutableHolder(T value)
    {
        this.Value = value;
    }
}

Затем сохранить вновь созданный MutableHolder<MapTile> в каждый слот словаря, а не хранить MapTile напрямую.Это позволит вам легко обновлять фрагмент карты, связанный с каким-либо конкретным ключом, без необходимости изменять сам словарь (действие, которое в противном случае, как минимум, лишит законной силы перечислитель, используемый вашим циклом foreach).

0 голосов
/ 27 апреля 2017

Структура шанса для класса

до:

public struct MapTile
{
    public int bgAnimation;
    public int bgFrame;
}

после:

public Class MapTile
{
    public int bgAnimation;
    public int bgFrame;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...