对二维数组中的每个元素执行一个操作

Performing an action for each element in a 2D array

我目前正在开发一款游戏,其中背景由二维图块阵列表示。 Tile 是一个相对简单的 class,包含图形和可遍历性信息。在我的代码中,我发现自己经常想做类似以下的事情:

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 保持不变。对于上面的示例,所有 Tiles 如果之前为 null,则仍然为 null。难道我做错了什么?有没有更好的方法来做我想做的事?

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

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

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
}

另一种方法(恕我直言,可能更简洁)是让操作委托 return 如果需要,一个新值:

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;
}