修改字典中的结构变量
Posted
技术标签:
【中文标题】修改字典中的结构变量【英文标题】:Modify Struct variable in a Dictionary 【发布时间】:2021-12-04 18:44:32 【问题描述】:我有一个这样的结构:
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++;
它给了我编译错误:
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
为什么我不能更改字典中的结构中的值?
【问题讨论】:
Ewww...可变结构。 (有人不得不说) 你没有在这里使用课程有什么原因吗? @Justin Niessner,为什么不好? @Lurler - 因为它们会导致大量混乱。人们开始像使用类一样使用它们,并期望它们的行为也与类相同……但事实并非如此(这就是您的代码存在问题的原因)。 @Lurler:这正是可变结构的问题——行为是有问题的。大多数时候,出于性能原因选择结构是过早的优化。最好将您的代码编写成可用和可维护的,然后进行分析,然后在必要时进行优化。在这种情况下,我怀疑这实际上会更快,尤其是如果它存储在字典中。 【参考方案1】:索引器将返回该值的副本。对该副本进行更改不会对字典中的值做任何事情...编译器阻止您编写错误代码。如果你想修改字典中的值,你需要使用类似的东西:
// 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;
【讨论】:
...这就是我发表评论而不是答案的原因。我知道当可变结构的话题出现时,Jon Skeet 也不会落后。 啊,现在我知道是什么问题了。感谢您的帮助! @JustinNiessner 不管怎样,Jon Skeet 提供了一个非常好的和简洁的答案!【参考方案2】: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;
【讨论】:
我认为结构不是引用类型,而是变量类型......奇怪。谢谢你的解释。 现在我也明白了为什么它们被认为是邪恶的 :) 我可能会在未来改变它的工作方式 :)struct
是值类型。值类型的显着特点是它们是按值复制的,相等是由值相等定义的。【参考方案3】:
我建议创建一个实用程序类:
public class MutableHolder<T>
public T Value;
public MutableHolder(T value)
this.Value = value;
然后将新创建的MutableHolder<MapTile>
存储到每个字典槽中,而不是直接存储MapTile
。这将允许您轻松更新与任何特定键关联的地图图块,而无需修改字典本身(否则,至少会使 foreach
循环使用的枚举器无效)。
【讨论】:
框架中是否已经有什么是我现在应该使用的通用 MutableHolder机会结构到类
之前:
public struct MapTile
public int bgAnimation;
public int bgFrame;
之后:
public Class MapTile
public int bgAnimation;
public int bgFrame;
【讨论】:
以上是关于修改字典中的结构变量的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Alamofire 获取请求中调用包含变量或常量的结构到字典中
程序通过定义学生结构体变量,存储学生的学号姓名和3门课的成绩。函数fun的功能是:对形参b所指结构体变量中的数据进行修改,并在主函数中输出修改后的数据。