在Dictionary中修改Struct变量

New*_*ger 33 c# foreach struct dictionary

我有这样的结构:

public struct MapTile
{
    public int bgAnimation;
    public int bgFrame;
}
Run Code Online (Sandbox Code Playgroud)

但当我用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++;
        }
}
Run Code Online (Sandbox Code Playgroud)

它给了我编译恐怖:

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
Run Code Online (Sandbox Code Playgroud)

为什么我不能在字典内的结构中更改值?

Jon*_*eet 44

索引器将返回值的副本.对该副本进行更改将不会对字典中的值执行任何操作...编译器阻止您编写错误代码.如果你想修改字典中的值,你需要使用类似的东西:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

请注意,这也是为了避免在原始代码执行的情况下进行多次查找.

我个人强烈建议不要开始使用可变结构,请注意......

当然,另一种方法是使其成为引用类型,此时您可以使用:

// 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;
}
Run Code Online (Sandbox Code Playgroud)

  • ......这就是我发表评论而非回答的原因.我知道当可变结构的主题出现时,Jon Skeet不能远远落后. (5认同)

jas*_*son 7

tilesData[tile.Key]不是存储位置(即,它不是变量).它是MapTiletile.Key字典中的键关联的实例的副本tilesData.这就是发生的事情struct.他们的实例的副本被传递并返回到处(并且是可变结构被认为是邪恶的很大一部分).

你需要做的是:

    MapTile tile = tilesData[tile.Key];
    if (tile.bgFrame >= tile.bgAnimation)
    {
        tile.bgFrame = 0;
    }
    else
    {
        tile.bgFrame++;
    }
    tilesData[tile.Key] = tile;
Run Code Online (Sandbox Code Playgroud)