Изменить переменную Struct в словаре

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

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

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

Вот код:

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

Это дает мне компиляцию:

 Error 1 Cannot modify the return value of 'System.Collections.Generic.Dictionary.this[string]' because it is not a variable Error 2 Cannot modify the return value of 'System.Collections.Generic.Dictionary.this[string]' because it is not a variable 

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

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

 // Note: copying the contents to start with as you can't modify a collection // while iterating over it foreach (KeyValuePair 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; } 

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; 

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

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

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

Шанс struct to Class

до:

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

после:

 public Class MapTile { public int bgAnimation; public int bgFrame; } 
  • Как я могу получить список значений из dict?
  • Std :: map, которые отслеживают порядок вставки?
  • Swagger: карта
  • Кортежи (или массивы) в качестве словарных ключей в C #
  • Определение, если словарь Swift содержит ключ и получает какие-либо его значения
  • Как извлечь все ключи (или значения) из std :: map и поместить их в вектор?
  • Проблема десериализации с помощью DataContractJsonSerializer
  • Есть ли у C # способ дать мне неизменный словарь?
  • Как получить содержимое словаря Викисловаря?
  • Hashtable с многомерным ключом в C #
  • Структуры данных, которые могут отображать диапазон ключей в значение
  • Давайте будем гением компьютера.