修改字典中的Struct变量
本文关键字:Struct 变量 字典 修改 | 更新日期: 2023-09-27 17:58:26
我有一个这样的结构:
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++;
}
}
它给了我编译arror:
Error 1 Cannot modify the return value of 'System.Collections.Generic.Dictionary<string,Warudo.MapTile>.this[string]' because it is not a variable
Error 2 Cannot modify the return value of 'System.Collections.Generic.Dictionary<string,Warudo.MapTile>.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<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;
}
tilesData[tile.Key]
不是存储位置(即,它不是变量)。它是与字典tilesData
中的关键字tile.Key
相关联的MapTile
的实例的副本。struct
就是这样。它们实例的副本到处传递和返回(这也是可变结构被认为是邪恶的原因之一)。
你需要做的是:
MapTile tile = tilesData[tile.Key];
if (tile.bgFrame >= tile.bgAnimation)
{
tile.bgFrame = 0;
}
else
{
tile.bgFrame++;
}
tilesData[tile.Key] = tile;
我建议创建一个实用程序类:
public class MutableHolder<T>
{
public T Value;
public MutableHolder(T value)
{
this.Value = value;
}
}
然后将新创建的MutableHolder<MapTile>
存储到每个字典槽中,而不是直接存储MapTile
。这将使您能够轻松更新与任何特定键关联的映射图块,而无需修改字典本身(否则,这一行为至少会使foreach
循环使用的枚举器无效)。
由于C#10.0(由@GuruStron友好修复),您可以使用with
语法来创建覆盖任意字段的旧结构的新副本。
mapTile = mapTile with { bgAnimation = 1 };
类的Chance结构
之前:
public struct MapTile
{
public int bgAnimation;
public int bgFrame;
}
之后:
public Class MapTile
{
public int bgAnimation;
public int bgFrame;
}