对 2D 数组中的每个元素执行操作

本文关键字:元素 执行 操作 2D 数组 | 更新日期: 2023-09-27 18:36:27

我目前正在开发一款游戏,其中背景由 2D 图块数组表示。磁贴是一个相对简单的类,其中包含图形和可遍历性信息。在我的代码中,我发现自己经常想做类似于以下内容的事情:

for (int x = 0; x < TileMap.GetLength(0); x++)
{
    for (int y = 0; y < TileMap.GetLength(1); y++)
    {
        // do something
    }
}

显然有更好的方法可以做到这一点,对吧?我想也许我可以创建一个扩展方法,该方法采用一个 Action 参数,该参数循环访问数组并为每个 Tile 执行指定的操作,如下所示:

public static void PerformAction(this Tile[,] tileMap, Action<Tile> action)
{
    for (int x = 0; x < tileMap.GetLength(0); x++)
    {
        for (int y = 0; y < tileMap.GetLength(1); y++)
        {
            action(tileMap[x, y]);
        }
    }
}

然后像这样使用它(只是一个示例):

TileMap.PerformAction(t => t = new Tile());

但是,这不起作用。我可以在扩展方法或 lambda 表达式中设置断点,并观察每次迭代都命中它,但 TileMap 中的实际 Tile 保持不变。对于上面的示例,如果之前所有磁贴为空,则它们仍然是空的。我做错了什么吗?有没有更好的方法来做我想做的事情?

对 2D 数组中的每个元素执行操作

从你的描述来看,听起来你希望能够修改数组本身中的元素,而不仅仅是它引用的对象(或它存储的值......不清楚Tileclass还是struct)。当然,调用Action<T>委托,您只是将值从数组传递给方法,而不是对数组元素的引用。在这种情况下,委托无法修改数组本身。

解决此问题的一种方法是传递数组 by-reference 的元素,而不是默认的 by-value。内置委托类型不支持按引用参数传递。但是您可以声明自己的委托(有关更多详细信息,请参阅此答案):

delegate void ActionRef<T>(ref T t);

然后,您可以像这样实现扩展方法:

public static void PerformAction(this Tile[,] tileMap, ActionRef<Tile> action)
{
    for (int x = 0; x < tileMap.GetLength(0); x++)
    {
        for (int y = 0; y < tileMap.GetLength(1); y++)
        {
            action(ref tileMap[x, y]);
        }
    }
}

从如下方法传递委托:

void MyActionMethod(ref Tile tile)
{
    // do something to tile
}

另一种方法(恕我直言,可能更干净一些)是在需要时让操作委托返回一个新值:

public static void PerformAction(this Tile[,] tileMap, Func<Tile, Tile> action)
{
    for (int x = 0; x < tileMap.GetLength(0); x++)
    {
        for (int y = 0; y < tileMap.GetLength(1); y++)
        {
            tileMap[x, y] = action(tileMap[x, y]);
        }
    }
}

然后,您的方法可能如下所示:

Tile MyActionMethod(Tile tile)
{
    // do something to tile
    return tile;
}